!7 cmodule TheoryMaker > DynConvo { /* 1. measurable features (fields of object) 2. higher level features (words the user throws in) 3. make theories (random statements) 4. check theories 1. show a random line 2. user types keyword 3. assign keyword to line (not yet used) line $a has keyword $x & line $a's text is $bla & line $y has text $bla => line $b might have keyword $x Basic theory making ------------------- For any label X: test theory (for every M: M has label X) test theory (for every M: M doesn't have label X) For any feature F: for every seen value V of F: for every label X: test theory (for every M: msg M's feature F has value V => msg has label x)) test theory (for every M: msg M's feature F has value V => msg doesn't have label x)) */ srecord Theory(BasicLogicRule statement) { PosNeg examples; } // propositions about a message srecord HasLabel(S label) {} srecord DoesntHaveLabel(S label) {} L msgs; // full dialog L shownMsgs; transient Map> msg2features = AutoMap<>(lambda1 calcMsgFeatures); new LinkedHashSet theories; S featuresText, trainedLabelsText, allLabelsText; new Set allLabels; transient new L> onNewLabel; new Map, Bool> msg2label; transient new Map> featureExtractors; start-thread { onNewLabel.add(lbl -> change()); // For any label X: onNewLabel.add(lbl -> { // test theory (for every M: M has label X) addTheory(new Theory(BasicLogicRule(null, HasLabel(x)))); // test theory (for every M: M doesn't have label X) addTheory(new Theory(BasicLogicRule(null, DoesntHaveLabel(x)))); }); for (S field : fields(Msg)) featureExtractors.put(field, o -> getOpt(o, field)); msg2labelUpdated(); dm_watchCollectionFieldAndNow allLabels(r allLabelsUpdated); if (empty(msgs)) setField(msgs := mainCruddieLog()); showRandomMsg(); } Map calcMsgFeatures(Msg msg) { ret mapValues_pcall(featureExtractors, ex -> ex.get(msg)); } void showMsgs(L l) { setField(shownMsgs := l); setMsgs(l); if (l(shownMsgs) == 1) setField(featuresText := formatColonProperties_quoteStringValues( msg2features.get(first(shownMsgs)))); else setField(featuresText := ""); } void showRandomMsg { showMsgs(randomElementAsList(msgs)); } @Override void sendInput2(S s) { // treat input as a label if (l(shownMsgs) == 1) { Msg shown = first(shownMsgs); new Matches m; if "not ..." { S label = m.rest(); mapPutVerbose(+msg2label, pair(shown, label), false); msg2labelUpdated(); } else { S label = s; mapPutVerbose(+msg2label, pair(shown, label), true); msg2labelUpdated(); } change(); } } Map getMsgLabels(Msg msg) { ret pairKeysToMapOfMap(msg2label).get(msg); } void msg2labelUpdated() { callFAllOnAll(onNewLabel, addAll_returnNew(allLabels, pairsBOfKeys(msg2label))); setField(trainedLabelsText := formatProperties(" => ", mapValues( map -> joinWithComma(concatLists( keysWithValue(true, map), prependAll("not ", keysWithValue(false, map)))), pairKeysToMapOfMap(msg2label)))); } void allLabelsUpdated() { setField(allLabelsText := lines(allLabels)); } JComponent mainPart() { ret jhsplit(jvsplit( jCenteredSection("Focused Message", super.mainPart()), jCenteredSection("Message Analysis", dm_textArea featuresText())), jtabs( "Labels", dm_textArea allLabelsText(), "Assigned Labels", dm_textArea trainedLabelsText())); } visual withCenteredButtons(super, "Show random msg", rThreadEnter showRandomMsg); void addTheory(Theory theory) { if (theories.add(theory)) { print("New theory: " + theory); change(); } } }