Java
Nova edição : ainda mais ajustes no tempo livre. Eu iniciei uma nova ramificação, onde eu tenho jogado com o algoritmo DFS. Oficialmente, o ramo deve atuar como o núcleo de um novo algoritmo de BFS que estou planejando, mas, enquanto isso, eu queria entender melhor o que o DFS está fazendo e como está tomando suas decisões. Para esse fim, adicionei uma função de supressão que começa a deteriorar o valor de uma nova palavra, independentemente de tópico ou não, à medida que as frases crescem mais. Além disso, todas as palavras contribuem com valor para a frase agora, mas as palavras que não estão no tópico ou na lista de tópicos da frase contribuem com apenas 25% do valor da frequência. Um exemplo de conversa pode ser encontrado aqui e é muito bom, onde falamos sobre física, a natureza humana do Chatbrains e outros tópicos fascinantes.código da filial aqui .
Edit : Eu estive ajustando o código um pouco. Em vez de postar as revisões aqui, confira no meu repositório do github, onde você encontrará as últimas revisões. Também adicionei uma nova conversa à versão mais recente, na qual discutimos chatbots, pesquisa em profundidade e como a programação deve ser usada para criar coisas vivas !.
Decidi abraçar esse desafio de forma holística. Meu chatbot sabe muito poucas coisas começando - sem palavras, sem sintaxe, sem nada. Ele sabe como analisar o inglês padrão em palavras e como identificar caracteres que não sejam palavras como pontuação. É isso aí. Tudo o que sabe aprende com a interação com o usuário. À medida que você interage, ele presta atenção às conexões entre palavras e constrói frases usando essas informações. Obviamente, consulte a fonte para obter mais informações. Excedeu em muito as expectativas de duração do programa recomendadas para esse desafio, mas com um bom objetivo. Aqui estão alguns destaques do programa:
- O Chatbot começa sem conhecimento (segue "Regras": 3 )
- A frequência da ocorrência de palavras é rastreada
- As frequências de palavras são "deterioradas" para que a conversa possa passar de tópico para tópico (segue "Bônus": 3 e 4 )
- O arranjo das palavras nas sentenças observadas é gravado, de modo que as "frases" são implicitamente controladas (por exemplo, se você usar muitas frases preposicionais ao conversar com o bot, o bot também usará muitas delas!)
- As frases são construídas preferindo seguir as conexões mais frequentemente observadas entre as palavras, com fatores aleatórios para injetar variação
- O algoritmo de construção de sentença é uma pesquisa de profundidade profunda, que tenta maximizar a ocorrência de palavras de tópico na sentença de saída, com uma pequena preferência por sentenças finais (segue "Bonus": 1 - Eu uso um algoritmo de aprendizado bastante legal, que muda ao longo do tempo e mantém o conhecimento das conexões de palavras coletadas)
- editar: as palavras dos tópicos agora são extraídas do conhecimento global de palavras recorrentes e da frase mais recente
- editar: os pesos das palavras agora são calculados usando a base de log 4 do comprimento das palavras; portanto, as palavras mais longas são mais pesadas e as mais curtas, mais fracas - isso é para compensar a falta de um corpus verdadeiro para usar tanto na ponderação quanto na eliminando palavras de alta frequência e baixo valor, como se pode fazer facilmente com um corpus.
- editar: À medida que o comprimento da frase aumenta durante a construção, uma função de supressão começa a diminuir o valor de palavras adicionais.
- editar: A frase "final" é menos valiosa agora, pois estava causando uma preponderância de frases curtas e tolas.
- editar: agora todas as palavras contribuem com valor, embora as palavras fora do tópico contribuam apenas com 25% do valor da frequência global.
- Existe uma profundidade máxima interna para evitar muitos ciclos e muito tempo gasto devido ao meu uso da palavra precedente para criar uma frase
- Os loops são detectados diretamente durante a criação de uma sentença e, embora tecnicamente permitidos, há uma grande chance de que os loops sejam evitados.
- O tempo limite de sintonia é usado para incentivar a remoção da ramificação e a finalização da instrução e também para evitar o atraso de 5 a 10 segundos nas regras
Para resumir minha conexão com as regras:
- Para "Regras": 1 , eu escolhi Java, que é detalhado, portanto seja gentil.
- Para "Rules": 2 , apenas a entrada do usuário é aproveitada, embora eu tenha algum código de stub para adicionar economia / carregamento do cérebro para o futuro
- Para "Regras": 3 , não existe absolutamente nenhum vocabulário predefinido. O ChatBot sabe como analisar o inglês, mas é isso. Começando, ele não sabe absolutamente nada.
- Para "Critérios obrigatórios": 1 , meu programa é mais longo, mas é bastante interessante. Espero que você esqueça.
- Para "Critérios obrigatórios": 2 , tenho um tempo limite no algoritmo de construção de sentenças para impedir explicitamente mais de 5-6 segundos no tempo de pesquisa. A melhor frase até agora é retornada com tempo limite.
- Para "Critérios obrigatórios": 3 , os tópicos geralmente se solidificam em cerca de 10 frases, de modo que o Bot estará no tópico até então e em 20 frases responderá a declarações com algumas construções aleatórias fascinantes que realmente fazem um pouco de sentido.
- Para "Critérios obrigatórios": 4 , não emprestei nada do código de referência. Esta é uma construção totalmente única.
- Para "Bonus": 1 , eu gosto de pensar que esse bot é bastante excepcional. Não será tão convincente quanto os bots com script, mas não tem absolutamente nenhuma limitação nos tópicos e se moverá normalmente (com persistência) de um tópico para outro.
- Para "Bonus": 2 , isso é estritamente round-robin, então nenhum bônus aqui. Ainda. Não há nenhum requisito no meu algoritmo para resposta, por isso estou planejando uma versão em Thread que abordará esse bônus.
- Para "Bonus": 3 , inicialmente esse bot imitará, mas conforme a conversa progride além das primeiras frases, a imitação terminará claramente.
- Para "Bônus": 4 , "humor" não é processado de maneira significativa, mas como o tópico de preferências do bot a seguir, ele mudará o humor.
- Para "Bônus": 5 , o salvamento e o carregamento do cérebro não estão disponíveis no momento.
Então, eu conheci todas as regras básicas, todas as regras obrigatórias e as regras de bônus provisórias 1, 3 e 4.
Como outro bônus, comentei em todo o código, fique à vontade para pedir emprestado ou fazer recomendações de melhorias. Claramente, como não tenho diálogo interno nem conhecimento "estrutural", as conversas serão estranhas por mais tempo do que outros bots, mas acho que cumpro as regras muito bem.
Agora, passe para o código (alguns comentários foram redigidos para se ajustarem ao limite do corpo) ou siga-o no GitHub, à medida que continuo aprimorando-o :
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();
}
}
}
Exemplo de conversa:
B / c vinculado de limites de caracteres de postagem
Conversa em que o Bot me diz que devo programar coisas vivas
Última conversa em que o Bot fala sobre a verdadeira natureza do Chatbrains, a física, o universo físico e como eu provavelmente também sou um Chatbrain
e assim por diante. Tenho algumas coisas que vou acrescentar - por exemplo, devido à semelhança de palavras simples, elas tendem a dominar listas de tópicos não curadas. Vou adicionar uma porcentagem de salto para as palavras do tópico, para que as palavras comuns sejam ignoradas.
Chatbot? Well the earth is fun place to talk about
- Ei, na verdade, ele fez sua própria sentença (compreensível) lá no final! : 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 ++
Agora só preciso escrever o algoritmo para iniciar uma conversa. Meu primeiro exercício de aprendizado de máquina.
Editar:
Todas as minhas tentativas foram ridículas, então acho que vou deixar assim. Os outros eram tão ridículos quanto isso:
fonte
C ++
Eu apontei para o bônus opcional 3: " Menos imitação, o comportamento do bot é diferente do comportamento do usuário, separando a percepção da atitude do bot da atitude do usuário ". O resultado foi um robô realmente teimoso que não consegue mudar de assunto com facilidade e deixa você louco.
Leva algum tempo para iniciar uma discussão, depois de um tempo uma discussão pode ser assim:
A abordagem é armazenar tudo em grupos de 3 palavras conectadas. Cada grupo é ponderado e re-ponderado em uma matriz de 1000 dimensões de grupos de palavras. Código fonte:
fonte
class c_wglist { ... } wgl;
. Funciona para mim. Tente init a variável wgl (classe c_wglist) em outro lugar.Python3 + SQLite3
Aqui está um pequeno bot que acabei de criar!
Como funciona?
Três tabelas SQL são usadas: uma para as palavras, uma para frases, uma para associar as palavras digitadas pelo usuário e a próxima frase que o bot deve exibir.
Quais são os recursos especiais?
Veja o código abaixo:
Aqui estão as três primeiras "conversas" que tive com o bot, começando em um banco de dados vazio:
Você pode dar uma olhada aqui para mais explicações.
fonte
Aqui está um que eu escrevi no Liberty BASIC há um tempo atrás. Não aprende, mas responde às diferentes respostas de suas perguntas.
conversa de exemplo:
fonte
HTML5
fonte
Fortran 95
Inspirado na resposta acima pelo usuário TheDoctor, decidi criar um chatbot engraçado de maneira semelhante. Esse código também não aprende, e eu o estou compartilhando aqui apenas por diversão.
Ele reconhece os seguintes termos e declarações: "sim" e "sim", "não" e "não", falta de pontuação ou tipos de pontuação (frases que terminam com "!", "?", "...") , frases que começam com "por que", "como" ou "o que", FRASES EM CAPS, riem (como "hahaha", "lol" e "kkk"), respostas muito curtas e muito longas, frases que contêm a palavra F, frase contendo as palavras "te amo" (tente pelo menos 3 vezes). Quando perguntar sobre o significado da vida, tente responder "42". Se ele perguntar se ele é mais esperto que o HAL 9000, responda a algo que contenha as palavras "verdadeiro", "verdade", "correto", "mentira", "falso" ou "falso". Se ele perguntar se você conhece uma piada em particular, responda "não" e deixe que ele diga a você. Se ele "bater, bater", responder "quem está aí?", Também o ajude com a fonte de uma cotação. Para sair, basta digitar "sair".
Exemplo de conversa:
PS: por favor, perdoe meu
goto
abuso, eu sei que todo esse código é uma espécie de confusão ... :)fonte