Java
New Edit : Noch mehr Optimierungen in der Freizeit. Ich habe einen neuen Zweig gestartet, in dem ich mit dem DFS-Algorithmus gespielt habe. Offiziell soll die Branche als Kern für einen neuen BFS-Algorithmus fungieren, den ich plane. In der Zwischenzeit wollte ich jedoch besser wissen, was die DFS tut und wie sie ihre Entscheidungen trifft. Zu diesem Zweck habe ich eine Unterdrückungsfunktion hinzugefügt, die den Wert eines neuen Wortes mit zunehmender Länge der Sätze unabhängig von der Thematik oder nicht zu verringern beginnt. Auch alle Wörter tragen jetzt zum Wert des Satzes bei, aber Wörter, die nicht in der Themen- oder Satzthemenliste enthalten sind, tragen nur 25% zu ihrem Häufigkeitswert bei. Ein Beispiel für ein Gespräch finden Sie hier. Es ist ziemlich gut, wenn wir über Physik, die menschliche Natur von Chatbrains und andere faszinierende Themen sprechen.Filialcode hier .
Bearbeiten : Ich habe den Code ein wenig optimiert. Anstatt die Revisionen hier zu veröffentlichen, schau in meinem Github-Repository nach, wo du die neuesten Revisionen findest. Ich habe auch eine neue Konversation gegen die neueste Version hinzugefügt, in der wir Chatbots, die Tiefensuche und die Verwendung der Programmierung zum Erstellen von Lebewesen erläutern.
Ich habe mich entschlossen, diese Herausforderung ganzheitlich anzunehmen. Mein Chatbot weiß nur sehr wenige Dinge - keine Wörter, keine Syntax, kein Nichts. Es versteht es, Standard-Englisch in Wörter zu zerlegen und Nicht-Wort-Zeichen als Interpunktion zu identifizieren. Das ist es. Alles, was es weiß, lernt es aus der Interaktion mit dem Benutzer. Während Sie damit interagieren, wird auf die Zusammenhänge zwischen Wörtern geachtet und anhand dieser Informationen werden Sätze gebildet. Weitere Informationen finden Sie in der Quelle. Ich habe die empfohlenen Programmdauererwartungen für diese Herausforderung deutlich übertroffen, aber zu einem guten Zweck. Hier einige Highlights des Programms:
- Chatbot startet ohne Wissen (folgt "Regeln": 3 )
- Die Häufigkeit des Wortauftretens wird verfolgt
- Die Worthäufigkeiten sind "verfallen", so dass die Konversation von Thema zu Thema wechseln kann (folgt "Bonus": 3 und 4 )
- Die Anordnung der Wörter in beobachteten Sätzen wird aufgezeichnet, so dass "Phrasen" implizit nachverfolgt werden (wenn Sie z. B. beim Chatten mit dem Bot viele Präpositionalphrasen verwenden, verwendet der Bot auch viele davon!).
- Sätze werden gebildet, indem man es vorzieht, den am häufigsten beobachteten Zusammenhängen zwischen Wörtern zu folgen, wobei zufällige Faktoren Variationen injizieren
- Der Satzkonstruktionsalgorithmus ist eine Tiefensuche, die versucht, das Vorkommen von Themenwörtern im Ausgabesatz zu maximieren, mit einer kleinen Präferenz für Endsätze (dies folgt "Bonus": 1 - Ich benutze einen verdammt coolen Lernalgorithmus, der verschiebt sich im Laufe der Zeit und behält das Wissen über geerntete Wortverbindungen)
- Bearbeiten: Themenwörter werden jetzt sowohl aus dem globalen Wissen über wiederkehrende Wörter als auch aus dem neuesten Satz gezogen
- Bearbeiten: Die Wortgewichtungen werden jetzt mit der logarithmischen Basis 4 der Wortlänge berechnet, sodass längere Wörter stärker und kürzere schwächer gewichtet werden - dies soll das Fehlen eines echten Korpus ausgleichen, der sowohl für die Gewichtung als auch für die Bewertung verwendet werden kann Entfernen von hochfrequenten Wörtern mit geringem Wert, wie dies mit einem Korpus problemlos möglich ist.
- edit: Wenn die Satzlänge während der Konstruktion zunimmt, verringert eine Unterdrückungsfunktion den Wert zusätzlicher Wörter.
- edit: Satz "Ende" ist jetzt weniger wertvoll, da es ein Übergewicht von kurzen albernen Sätzen verursachte.
- Bearbeiten: Alle Wörter tragen jetzt zum Wert bei, obwohl Wörter außerhalb des Themas nur zu 25% zum globalen Häufigkeitswert beitragen.
- Es gibt ein integriertes Tiefenmaximum, um zu verhindern, dass zu viele Schleifen ausgeführt werden und zu viel Zeit aufgewendet wird, da ich zum Erstellen eines Satzes Präzedenzfälle verwende
- Schleifen werden direkt beim Erstellen eines Satzes erkannt, und obwohl dies technisch zulässig ist, besteht eine hohe Wahrscheinlichkeit, dass Schleifen vermieden werden
- Das Zeitlimit für die Optimierung wird verwendet, um sowohl das Bereinigen von Zweigen als auch das Abschließen von Anweisungen zu fördern und um zu verhindern, dass die "akzeptable Verzögerung" von 5 bis 10 Sekunden in den Regeln überschritten wird
Um meine Verbindung zu den Regeln zusammenzufassen:
- Für "Rules": 1 habe ich Java gewählt, was sehr ausführlich ist. Seien Sie also vorsichtig.
- Für "Rules": 2 wird nur die Benutzereingabe genutzt, obwohl ich einige Stub-Codes habe, um für die Zukunft das Speichern / Laden des Gehirns hinzuzufügen
- Für "Regeln": 3 gibt es absolut keinen voreingestellten Wortschatz. Der ChatBot kann Englisch analysieren, aber das war's. Anfangs weiß es absolut nichts.
- Für "Obligatorische Kriterien": 1 , mein Programm ist länger, aber es packt viel Geiles. Ich hoffe, Sie übersehen.
- Zum "Obligatorische Kriterien": 2 habe ich eine Zeitüberschreitung für meinen Satzkonstruktionsalgorithmus, um explizit eine Suchzeit von mehr als 5 bis 6 Sekunden zu verhindern. Der bisher beste Satz wird bei Timeout zurückgegeben.
- Für "Obligatorische Kriterien": 3 sind die Themen in der Regel in etwa 10 Sätzen zusammengefasst, sodass der Bot bis dahin über das Thema informiert ist und 20 Sätze auf Aussagen mit einigen faszinierenden Zufallskonstrukten reagieren, die tatsächlich Sinn ergeben.
- Für "Obligatorische Kriterien": 4 ich nichts aus dem Referenzcode ausgeliehen. Dies ist eine völlig einzigartige Konstruktion.
- Für "Bonus": 1 halte ich diesen Bot für außergewöhnlich. Es ist nicht so überzeugend wie Bots mit Skripten, hat jedoch keinerlei Einschränkungen in Bezug auf Themen und bewegt sich elegant (mit Beharrlichkeit) von Gesprächsthema zu Thema.
- Bei "Bonus": 2 handelt es sich um ein Round-Robin-Verfahren, daher hier kein Bonus. Noch. Mein Algorithmus erfordert keine Antwort, daher plane ich eine Thread-Version, die diesen Bonus berücksichtigt.
- Für "Bonus": 3 ahmt dieser Bot zunächst nach, aber wenn das Gespräch über die ersten Sätze hinausgeht, endet die Nachahmung eindeutig.
- Für "Bonus": 4 werden "Stimmungen" nicht in irgendeiner Weise verarbeitet, aber da das folgende Thema der Bot-Präferenzen folgt, werden die Stimmungen geändert.
- Für "Bonus": 5 ist das Speichern und Laden von Gehirn derzeit nicht vorhanden.
Also habe ich alle Grundregeln, alle obligatorischen Regeln und die vorläufigen Bonusregeln 1, 3 und 4 erfüllt.
Als weiteren Bonus habe ich den gesamten Code kommentiert. Sie können ihn also ausleihen oder Empfehlungen für Verbesserungen abgeben. Klar, da ich keinen eingebauten Dialog und keine "strukturellen" Kenntnisse habe, werden Gespräche länger seltsam sein als andere Bots, aber ich denke, ich erfülle die Regeln ziemlich gut.
Nun zu dem Code (Einige Kommentare wurden angepasst, um den Body Limit zu erreichen) oder folge ihm auf GitHub, während ich ihn weiter verbessere :
import java.util.*;
import java.util.regex.*;
public class LearningChatbot {
/**
* Static definition of final word in a statement. It never has
* any descendents, and concludes all statements. This is the only
* "starting knowledge" granted the bot.
*/
public static final ChatWord ENDWORD = new ChatWord("\n");
/**
* The Brain of this operation.
*/
private ChatbotBrain brain;
/**
* Starts LearningChatbot with a new brain
*/
public LearningChatbot() {
brain = new ChatbotBrain();
}
/**
* Starts LearningChatbot with restored brain.
*/
public LearningChatbot(String filename) {
throw new UnsupportedOperationException("Not yet implemented");
}
/**
* Invocation method.
*/
public void beginConversation() {
ChatbotBrain cb = new ChatbotBrain();
Scanner dialog = new Scanner(System.in);
boolean more = true;
while (more) {
System.out.print(" You? ");
String input = dialog.nextLine();
if (input.equals("++done")) {
System.exit(0);
} else if (input.equals("++save")) {
System.out.println("Saving not yet implemented, sorry!");
System.exit(0);
} else if (input.equals("++help")) {
getHelp();
}else {
cb.decay();
cb.digestSentence(input);
}
System.out.print("Chatbot? ");
System.out.println(cb.buildSentence());
}
}
/**
* Help display
*/
public static void getHelp() {
System.out.println("At any time during the conversation, type");
System.out.println(" ++done");
System.out.println("to exit without saving.");
System.out.println("Or type");
System.out.println(" ++save");
System.out.println("to exit and save the brain.");
System.out.println();
}
/**
* Get things started.
*/
public static void main(String[] args) {
System.out.println("Welcome to the Learning Chatbot");
System.out.println();
getHelp();
LearningChatbot lc = null;
if (args.length > 0) {
System.out.printf("Using %s as brain file, if possible.", args[0]);
lc = new LearningChatbot(args[0]);
} else {
lc = new LearningChatbot();
}
lc.beginConversation();
}
/**
* The ChatbotBrain holds references to all ChatWords and has various
* methods to decompose and reconstruct sentences.
*/
static class ChatbotBrain {
/**
* A tracking of all observed words. Keyed by the String version of
* the ChatWord, to allow uniqueness across all ChatWords
*/
private Map<String,ChatWord> observedWords;
/**
* This brain is going to be able to keep track of "topics" by way of
* a word frequency map. That way, it can generate sentences based
* on topic-appropriateness.
*/
private Map<ChatWord, Double> wordFrequencyLookup;
/**
* This holds the actual word frequencies, for quick isolation of
* highest frequency words.
*/
private NavigableMap<Double, Collection<ChatWord>> wordFrequency;
/**
* This holds the count of words observed total.
*/
private int wordCount;
/**
* This holds the current "values" of all words.
*/
private double wordValues;
/**
* A "word" that is arbitrarily the start of every sentence
*/
private ChatWord startWord;
/**
* Rate of decay of "topics".
*/
private double decayRate;
// These values configure various features of the recursive
// sentence construction algorithm.
/** Nominal (target) length of sentences */
public static final int NOMINAL_LENGTH = 10;
/** Max length of sentences */
public static final int MAX_LENGTH = 25;
/** Sentence creation timeout */
public static final long TIMEOUT = 5000;
/** Topic words to match against */
public static final int TOPICS = 3;
/** Minimum branches to consider for each word */
public static final int MIN_BRANCHES = 3;
/** Maximum branches to consider for each word */
public static final int MAX_BRANCHES = 5;
/** % chance as integer out of 100 to skip a word */
public static final int SKIP_CHANCE = 20;
/** % chance as integer to skip a word that would cause a loop */
public static final int LOOP_CHANCE = 5;
/** % chance that punctuation will happen at all */
public static final int PUNCTUATION_CHANCE = 25;
/** % chance that a particular punctuation will be skipped */
public static final int PUNCTUATION_SKIP_CHANCE = 40;
/**
* Convenience parameter to use a common random source
* throughout the brain.
*/
private Random random;
/**
* Gets the Chatbot started, sets up data structures necessary
*/
public ChatbotBrain() {
observedWords = new HashMap<String,ChatWord>();
observedWords.put("\n",ENDWORD);
startWord = new ChatWord("");
observedWords.put("",startWord);
wordFrequencyLookup = new HashMap<ChatWord, Double>();
wordFrequency = new TreeMap<Double, Collection<ChatWord>>();
decayRate = 0.05;
wordCount = 0;
wordValues = 0.0;
random = new Random();
}
/**
* More complex digest method (second edition) that takes a sentence,
* cuts it pu, and links up the words based on ordering.
*/
public void digestSentence(String sentence) {
Scanner scan = new Scanner(sentence);
ChatWord prior = null;
ChatWord current = null;
String currentStr = null;
String currentPnc = null;
while (scan.hasNext()) {
currentStr = scan.next();
Pattern wordAndPunctuation =
Pattern.compile("([a-zA-Z\\-_'0-9]+)([^a-zA-Z\\-_'0-9]?)[^a-zA-Z\\-_'0-9]*?");
Matcher findWords = wordAndPunctuation.matcher(currentStr);
// Basically this lets us find words-in-word typos like this:
// So,bob left his clothes with me again.
// where "So,bob" becomes "So," "bob"
while (findWords.find()) {
currentStr = findWords.group(1);
currentPnc = findWords.group(2);
if (currentStr != null) {
if (observedWords.containsKey(currentStr)) {
current = observedWords.get(currentStr);
} else {
current = new ChatWord(currentStr);
observedWords.put(currentStr, current);
}
incrementWord(current);
if (currentPnc != null && !currentPnc.equals("")) {
current.addPunctuation(currentPnc.charAt(0));
}
if (prior != null) {
prior.addDescendent(current);
}
if (prior == null) {
startWord.addDescendent(current);
}
prior = current;
}
}
}
if (prior != null) { // finalize.
prior.addDescendent(ENDWORD);
}
}
/**
* Increments the value of a word (catalogues a new sighting).
*/
public void incrementWord(ChatWord word) {
Double curValue;
Double nextValue;
Collection<ChatWord> freqMap;
if (wordFrequencyLookup.containsKey(word)) {
curValue = wordFrequencyLookup.get(word);
freqMap = wordFrequency.get(curValue);
freqMap.remove(word);
} else {
curValue = 0.0;
}
nextValue=curValue+1.0;
wordFrequencyLookup.put(word, nextValue);
freqMap = wordFrequency.get(nextValue);
if (freqMap == null) {
freqMap = new HashSet<ChatWord>();
wordFrequency.put(nextValue, freqMap);
}
freqMap.add(word);
wordCount++;
wordValues++;
}
/**
* Decays a particular word by decay rate.
*/
public void decayWord(ChatWord word) {
Double curValue;
Double nextValue;
Collection<ChatWord> freqMap;
if (wordFrequencyLookup.containsKey(word)) {
curValue = wordFrequencyLookup.get(word);
freqMap = wordFrequency.get(curValue);
freqMap.remove(word);
} else {
return;
}
wordValues-=curValue; // remove old decay value
nextValue=curValue-(curValue*decayRate);
wordValues+=nextValue; // add new decay value
wordFrequencyLookup.put(word, nextValue);
freqMap = wordFrequency.get(nextValue);
if (freqMap == null) {
freqMap = new HashSet<ChatWord>();
wordFrequency.put(nextValue, freqMap);
}
freqMap.add(word);
}
/**
* Decay all word's frequency values.
*/
public void decay() {
for (ChatWord cw : wordFrequencyLookup.keySet()) {
decayWord(cw);
}
}
/**
* Gets a set of words that appear to be "top" of the frequency
* list.
*/
public Set<ChatWord> topicWords(int maxTopics) {
Set<ChatWord> topics = new HashSet<ChatWord>();
int nTopics = 0;
for (Double weight: wordFrequency.descendingKeySet()) {
for (ChatWord word: wordFrequency.get(weight)) {
topics.add(word);
nTopics++;
if (nTopics == maxTopics) {
return topics;
}
}
}
return topics;
}
/**
* Uses word frequency records to prefer to build on-topic
* sentences.
*/
public String buildSentence() {
int maxDepth = NOMINAL_LENGTH+
random.nextInt(MAX_LENGTH - NOMINAL_LENGTH);
ChatSentence cs = new ChatSentence(startWord);
// We don't want to take too long to "think of an answer"
long timeout = System.currentTimeMillis() + TIMEOUT;
double bestValue = buildSentence(cs, topicWords(TOPICS), 0.0, 0, maxDepth, timeout);
return cs.toString();
}
public double buildSentence(ChatSentence sentence,
Set<ChatWord> topics, double curValue,
int curDepth, int maxDepth, long timeout){
if (curDepth==maxDepth || System.currentTimeMillis() > timeout) {
return curValue;
}
// Determine how many branches to enter from this node
int maxBranches = MIN_BRANCHES + random.nextInt(MAX_BRANCHES - MIN_BRANCHES);
// try a few "best" words from ChatWord's descendent list.
ChatWord word = sentence.getLastWord();
NavigableMap<Integer, Collection<ChatWord>> roots =
word.getDescendents();
// Going to keep track of current best encountered sentence
double bestSentenceValue = curValue;
ChatSentence bestSentence = null;
int curBranches = 0;
for (Integer freq : roots.descendingKeySet()) {
for (ChatWord curWord : roots.get(freq)) {
if (curWord.equals(ENDWORD)) {
// let's weigh the endword cleverly
double endValue = random.nextDouble() * wordFrequency.lastKey();
if (curValue+endValue > bestSentenceValue) {
bestSentenceValue = curValue+endValue;
bestSentence = new ChatSentence(sentence);
bestSentence.addWord(curWord);
}
curBranches++;
} else {
int chance = random.nextInt(100);
boolean loop = sentence.hasWord(curWord);
/* Include a little bit of chance in the inclusion of
* any given word, whether a loop or not.*/
if ( (!loop&&chance>=SKIP_CHANCE) ||
(loop&&chance<LOOP_CHANCE)) {
double wordValue = topics.contains(curWord)?
wordFrequencyLookup.get(curWord):0.0;
ChatSentence branchSentence = new ChatSentence(sentence);
branchSentence.addWord(curWord);
addPunctuation(branchSentence);
double branchValue = buildSentence(branchSentence,
topics, curValue+wordValue, curDepth+1,
maxDepth, timeout);
if (branchValue > bestSentenceValue) {
bestSentenceValue = branchValue;
bestSentence = branchSentence;
}
curBranches++;
}
}
if (curBranches == maxBranches) break;
}
if (curBranches == maxBranches) break;
}
if (bestSentence != null) {
sentence.replaceSentence(bestSentence);
}
return bestSentenceValue;
}
/**
* Adds punctuation to a sentence, potentially.
*/
public void addPunctuation(ChatSentence sentence) {
ChatWord word = sentence.getLastWord();
NavigableMap<Integer, Collection<Character>> punc = word.getPunctuation();
if (punc.size()>0 && random.nextInt(100)<PUNCTUATION_CHANCE){
Integer puncMax = punc.lastKey();
Collection<Character> bestPunc = punc.get(puncMax);
Character puncPick = null;
for (Integer freq : punc.descendingKeySet()) {
for (Character curPunc : punc.get(freq)) {
if (random.nextInt(100)>=PUNCTUATION_SKIP_CHANCE) {
puncPick = curPunc;
break;
}
}
if (puncPick != null) break;
}
if (puncPick != null) {
sentence.addCharacter(puncPick);
}
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("ChatBrain[");
sb.append(observedWords.size());
sb.append("]:");
for (Map.Entry<String,ChatWord> cw : observedWords.entrySet()) {
sb.append("\n\t");
sb.append(wordFrequencyLookup.get(cw.getValue()));
sb.append("\t");
sb.append(cw.getValue());
}
return sb.toString();
}
}
/**
* Useful helper class to construct sentences.
*/
static class ChatSentence implements Cloneable {
/**
* List of words.
*/
private List<Object> words;
/**
* Quick search construct to have O(ln) lookup times.
*/
private Set<Object> contains;
/**
* Starts to build a sentence with a single word as anchor
*/
public ChatSentence(ChatWord anchor) {
if (anchor == null) {
throw new IllegalArgumentException("Anchor must not be null");
}
words = new ArrayList<Object>();
contains = new HashSet<Object>();
words.add(anchor);
contains.add(anchor);
}
/**
* Starts a sentence using an existing ChatSentence. Also used for
* cloning.
*/
public ChatSentence(ChatSentence src) {
words = new ArrayList<Object>();
contains = new HashSet<Object>();
appendSentence(src);
}
/**
* Adds a word to a sentence
*/
public ChatSentence addWord(ChatWord word) {
if (word == null) {
throw new IllegalArgumentException("Can't add null word");
}
words.add(word);
contains.add(word);
return this;
}
/**
* Adds a character to a sentence.
*/
public ChatSentence addCharacter(Character punc) {
if (punc == null) {
throw new IllegalArgumentException("Can't add null punctuation");
}
words.add(punc);
contains.add(punc);
return this;
}
/**
* Replace a sentence with some other sentence.
* Useful to preserve references.
*/
public ChatSentence replaceSentence(ChatSentence src) {
words.clear();
contains.clear();
appendSentence(src);
return this;
}
public ChatSentence appendSentence(ChatSentence src) {
words.addAll(src.getWords());
contains.addAll(src.getWords());
return this;
}
/**
* Get last word of the sentence.
*/
public ChatWord getLastWord() {
for (int i=words.size()-1; i>=0; i--) {
if (words.get(i) instanceof ChatWord) {
return (ChatWord) words.get(i);
}
}
throw new IllegalStateException("No ChatWords found!");
}
/**
* Checks if the sentence has a word
*/
public boolean hasWord(ChatWord word) {
return contains.contains(word);
}
/**
* Counts the number of words in a sentence.
*/
public int countWords() {
int cnt = 0;
for (Object o : words) {
if (o instanceof ChatWord) {
cnt++;
}
}
return cnt;
}
/**
* Gets all the words of the sentence
*/
private List<Object> getWords() {
return words;
}
/**
* Returns the sentence as a string.
*/
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
for (Object o : words) {
if (o instanceof ChatWord) {
ChatWord cw = (ChatWord) o;
sb.append(" ");
sb.append( cw.getWord() );
} else {
sb.append(o);
}
}
return sb.toString().trim();
}
/**
* Clones this sentence.
*/
@Override
public Object clone() {
return new ChatSentence(this);
}
}
/**
* ChatWord allows the creation of words that track how they are
* connected to other words in a forward fashion.
*/
static class ChatWord {
/** The word. */
private String word;
/** Collection of punctuation observed after this word */
private NavigableMap<Integer, Collection<Character>> punctuation;
/** Lookup linking observed punctuation to where they are in ordering */
private Map<Character, Integer> punctuationLookup;
/** Punctionation observation count */
private Integer punctuationCount;
/** Collection of ChatWords observed after this word */
private NavigableMap<Integer, Collection<ChatWord>> firstOrder;
/** Lookup linking observed words to where they are in ordering */
private Map<ChatWord, Integer> firstOrderLookup;
/** First order antecedent word count */
private Integer firstOrderCount;
/**
* Creates a new ChatWord that is aware of punctuation that
* follows it, and also ChatWords that follow it.
*/
public ChatWord(String word){
this.word = word;
this.firstOrder = new TreeMap<Integer, Collection<ChatWord>>();
this.firstOrderLookup = new HashMap<ChatWord, Integer>();
this.firstOrderCount = 0;
this.punctuation = new TreeMap<Integer, Collection<Character>>();
this.punctuationLookup = new HashMap<Character, Integer>();
this.punctuationCount = 0;
}
protected NavigableMap<Integer, Collection<ChatWord>> getDescendents() {
return firstOrder;
}
/**
* Returns how many descendents this word has seen.
*/
protected int getDescendentCount() {
return firstOrderCount;
}
/**
* Gets the lookup map for descendents
*/
protected Map<ChatWord, Integer> getDescendentsLookup() {
return firstOrderLookup;
}
/** As conversation progresses, word orderings will be encountered.
* The descendent style of "learning" basically weights how often
* words are encountered together, and is strongly biased towards
* encountered ordering.
*/
public void addDescendent(ChatWord next) {
if(next != null){
firstOrderCount++;
int nextCount = 1;
Collection<ChatWord> obs = null;
// If we've already seen this word, clean up prior membership.
if(firstOrderLookup.containsKey(next)){
nextCount = firstOrderLookup.remove(next);
obs = firstOrder.get(nextCount);
// Remove from prior obs count order
obs.remove(next);
nextCount++;
}
obs = firstOrder.get(nextCount);
if (obs == null) { // we don't have this order yet
obs = new HashSet<ChatWord>();
firstOrder.put(nextCount, obs);
}
firstOrderLookup.put(next, nextCount);
obs.add(next);
}
}
/**
* Some words have punctuation after them more often than not.
* This allows the ChatBrain to record occurrences of punctuation
* after a word.
*/
public void addPunctuation(Character punc) {
if(punc != null){
punctuationCount++;
int puncCount = 1;
Collection<Character> obs = null;
// If we've already seen this punc, clean up prior membership.
if(punctuationLookup.containsKey(punc)){
puncCount = punctuationLookup.remove(punc);
obs = punctuation.get(puncCount);
// Remove from prior obs count order
obs.remove(punc);
puncCount++;
}
obs = punctuation.get(puncCount);
if (obs == null) { // we don't have this order yet
obs = new HashSet<Character>();
punctuation.put(puncCount, obs);
}
punctuationLookup.put(punc, puncCount);
obs.add(punc);
}
}
/**
* Including this for now, but I don't like it -- it returns all
* punctuation wholesale. I think what would be better is some
* function that returns punctuation based on some characteristic.
*/
protected NavigableMap<Integer, Collection<Character>> getPunctuation() {
return punctuation;
}
/**
* Gets count of punctuation encountered.
*/
protected int getPunctuationCount() {
return punctuationCount;
}
/**
* Gets lookup of punctuations encountered.
*/
protected Map<Character, Integer> getPunctuationLookup() {
return punctuationLookup;
}
/**
* Gets the String backing this ChatWord.
*/
public String getWord() {
return word;
}
/**
* ChatWords are equivalent with the String they wrap.
*/
@Override
public int hashCode() {
return word.hashCode();
}
/**
* ChatWord equality is that ChatWords that wrap the same String
* are equal, and a ChatWord is equal to the String that it contains.
*/
@Override
public boolean equals(Object o){
if (o == this) {
return true;
}
if (o instanceof ChatWord) {
return ((ChatWord)o).getWord().equals(this.getWord());
}
if (o instanceof String) {
return ((String)o).equals(this.getWord());
}
return false;
}
/**
* Returns this ChatWord as a String.
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("ChatWord[");
sb.append(word);
sb.append("]desc{");
for (Integer key : firstOrder.keySet() ) {
Collection<ChatWord> value = firstOrder.get(key);
sb.append(key);
sb.append(":[");
for (ChatWord cw : value) {
sb.append(cw.getWord());
sb.append(",");
}
sb.append("],");
}
sb.append("}punc{");
for (Integer key : punctuation.keySet() ) {
Collection<Character> value = punctuation.get(key);
sb.append(key);
sb.append(":[");
for (Character c : value) {
sb.append("\"");
sb.append(c);
sb.append("\",");
}
sb.append("],");
}
sb.append("}");
return sb.toString();
}
}
}
Beispielgespräch:
Verbundenes b / c der Nachzeichenbegrenzungen
Gespräch, bei dem der Bot mir sagt, ich solle Lebewesen programmieren
Letzte Unterhaltung, in der der Bot über die wahre Natur von Chatbrains, die Physik, das physikalische Universum und wie ich höchstwahrscheinlich auch ein Chatbrain bin, spricht
und so weiter. Ich möchte ein paar Dinge hinzufügen, zum Beispiel, weil einfache Wörter häufig vorkommen, dass sie ungekurierte Themenlisten dominieren. Ich werde Themenwörter prozentual überspringen, damit gebräuchliche Wörter übersprungen werden.
Chatbot? Well the earth is fun place to talk about
- Hey, es hat dort am Ende tatsächlich einen eigenen (verständlichen) Satz gemacht! : D +1Chatbot? I'm not a Chatbrain since Chatbrains are the physical universe,
.The answer to the ultimate question about life, the universe, and everything is 'SyntaxError: missing ; before statement'.
C ++
Jetzt muss ich nur noch den Algorithmus schreiben, um ein Gespräch fortzusetzen. Meine erste maschinelle Lernübung.
Bearbeiten:
Alle meine Versuche fielen lächerlich aus, also denke ich, dass ich es so lassen werde. Die anderen waren sowieso genauso lächerlich:
quelle
C ++
Ich strebte den optionalen Bonus 3 an: " Weniger imitierend, Bot-Verhalten unterscheidet sich vom Benutzerverhalten, wodurch die Wahrnehmung der Bot-Haltung von der Benutzereinstellung getrennt wird. " Das Ergebnis war ein wirklich hartnäckiger Bot, der das Thema nicht einfach wechseln kann und Sie verrückt macht.
Es dauert eine Weile, bis eine Diskussion in Gang kommt. Nach einer Weile kann eine Diskussion so aussehen:
Der Ansatz besteht darin, alles in Gruppen von 3 verbundenen Wörtern zu speichern. Jede Gruppe wird gewichtet und in eine 1000-dimensionale Matrix von Wortgruppen neu gewichtet. Quellcode:
quelle
class c_wglist { ... } wgl;
. Für mich geht das. Versuchen Sie, die Variable wgl (Klasse c_wglist) an einer anderen Stelle zu initialisieren.Python3 + SQLite3
Hier ist ein kleiner Bot, den ich gerade gemacht habe!
Wie funktioniert es?
Es werden drei SQL-Tabellen verwendet: eine für die Wörter, eine für die Sätze, eine für die Zuordnung der vom Benutzer eingegebenen Wörter zum nächsten Satz, den der Bot anzeigen soll.
Was sind die Besonderheiten?
Siehe Code unten:
Hier sind die drei ersten "Gespräche", die ich mit dem Bot geführt habe, beginnend mit einer leeren Datenbank:
Sie können hier nachsehen , um weitere Erklärungen zu erhalten.
quelle
Hier ist eine, die ich vor einiger Zeit in Liberty BASIC geschrieben habe. Es lernt nicht, aber es antwortet auf die unterschiedlichen Antworten seiner Fragen.
Beispiel Gespräch:
quelle
HTML5
quelle
Fortran 95
Inspiriert von der obigen Antwort des Benutzers TheDoctor, habe ich beschlossen, auf ähnliche Weise einen lustigen Chatbot zu erstellen. Dieser Code lernt auch nicht und ich teile ihn hier nur zum Spaß.
Es erkennt die folgenden Ausdrücke und Aussagen an: "Ja" und "Ja", "Nein" und "Nein", fehlende Interpunktion oder Interpunktionsarten (Ausdrücke, die mit "!", "?", "..." enden) , Sätze, die mit "warum", "wie" oder "was" beginnen, Sätze in Großbuchstaben, Lachen (wie "hahaha", "lol" und "kkk"), sehr kurze und sehr lange Antworten, Sätze, die das F-Wort, Satz enthalten mit den Worten "Liebe dich" (probiere es mindestens 3 mal). Wenn Sie nach dem Sinn des Lebens gefragt werden, antworten Sie mit "42". Wenn Sie gefragt werden, ob er schlauer als HAL 9000 ist, antworten Sie auf etwas, das die Wörter "wahr", "wahr", "richtig", "lügen", "falsch" oder "unwahr" enthält. Wenn er fragt, ob Sie einen bestimmten Witz kennen, antworte mit "nein" und lass es dir sagen. Wenn er "klopft", antworte "wer ist da?", Hilf ihm auch mit der Quelle eines Zitats. Geben Sie zum Beenden einfach "quit" ein.
Beispiel für ein Gespräch:
PS: bitte vergib mir meinen
goto
Missbrauch, ich weiß, dass dieser ganze Code eine Art Durcheinander ist ... :)quelle