Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

600
LINES

< > BotCompany Repo | #1028066 // Auto Classifier v5 [learning message classifier]

JavaX source code (Dynamic Module) [tags: use-pretranspiled] - run with: Stefan's OS

Uses 911K of libraries. Click here for Pure Java version (20530L/109K).

1  
!7
2  
3  
cmodule AutoClassifier > DynConvo {
4  
  // THEORY BUILDING BLOCKS (Theory + MsgProp + subclasses)
5  
  
6  
  srecord Theory(BasicLogicRule statement) {
7  
    new PosNeg<Msg> examples;
8  
    //bool iff; // <=> instead of only =>
9  
    toString { ret str(statement.lhs instanceof MPTrue ? "Every message is " + statement.rhs
10  
      : bidiMode ? statement.lhs + " <=> " + statement.rhs : statement); }
11  
  }
12  
13  
  // propositions about a message. check returns null if unknown
14  
  asclass MsgProp { abstract Bool check(Msg msg); }
15  
16  
  static transformable record MPTrue() > MsgProp {
17  
    Bool check(Msg msg) { true; }
18  
    toString { ret "always"; }
19  
  }
20  
  
21  
  transformable record HasLabel(S label) > MsgProp {
22  
    Bool check(Msg msg) { ret msg2label_new.get(msg, label); }
23  
    toString { ret label; }
24  
  }
25  
  
26  
  transformable record DoesntHaveLabel(S label) > MsgProp {
27  
    Bool check(Msg msg) { ret not(msg2label_new.get(msg, label)); }
28  
    toString { ret "not " + label; }
29  
  }
30  
31  
  transformable record FeatureValueIs(S feature, O value) > MsgProp {
32  
    Bool check(Msg msg) { ret eq(getMsgFeature(msg, feature), value); }
33  
    toString { ret feature + "=" + value; }
34  
  }
35  
  
36  
  // feature extracts the text from msg
37  
  transformable record MMOMatch(S feature, S pattern) > MsgProp {
38  
    Bool check(Msg msg) { ret mmo_match2(pattern, (S) getMsgFeature(msg, feature)); }
39  
    toString { ret renderFunctionCall("MMOMatch", pattern, feature); }
40  
  }
41  
  
42  
  // LABEL class (with best theories)
43  
44  
  class Label {
45  
    S name;
46  
47  
    *() {}
48  
    *(S *name) {}
49  
    
50  
    TreeSetWithDuplicates<Theory> bestTheories = new(reverseComparatorFromCalculatedField theoryScore());
51  
52  
    double score() { ret theoryScore(first(bestTheories)); }
53  
    Theory bestTheory() { ret first(bestTheories); }
54  
  }
55  
  
56  
  // FEATURE base classes (FeatureEnv + FeatureExtractor)
57  
  
58  
  sinterface FeatureEnv<A> {
59  
    A mainObject();
60  
    O getFeature(S name);
61  
  }
62  
63  
  sinterface FeatureExtractor<A> {
64  
    O get(FeatureEnv<A> env);
65  
  }
66  
  
67  
  // PREDICTION class (output of classifier)
68  
  
69  
  srecord Prediction(S label, bool plus, double adjustedConfidence) {
70  
    toString {
71  
      ret predictedLabel() + " (confidence: " + iround(adjustedConfidence) + "%)";
72  
    }
73  
74  
    S predictedLabel() {
75  
      ret (plus ? "" : "not ") + label;
76  
    }
77  
  }
78  
79  
  // DATA (backend)
80  
  
81  
  sbool bidiMode = true; // treat all theories as bidirectional
82  
  L<Msg> msgs; // all messages (order not used yet)
83  
  transient Map<Msg, MapSO> msg2features = new AutoMap<Msg, MapSO>(lambda1 calcMsgFeatures);
84  
  Set<S> allLabels = syncTreeSet();
85  
  transient new Map<S, Label> labelsByName;
86  
  new LinkedHashSet<Theory> theories;
87  
  transient Q thinkQ;
88  
  transient new L<IVF1<S>> onNewLabel;
89  
  new DoubleKeyedMap<Msg, S, Bool> msg2label_new;
90  
  transient new Map<S, FeatureExtractor<Msg>> featureExtractors;
91  
  
92  
  // DATA (GUI)
93  
  
94  
  switchable double minAdjustedScoreToDisplay = 50;
95  
  switchable bool autoNext = false;
96  
  L<Msg> shownMsgs;
97  
  S analysisText, labelsForMsgText;
98  
  transient JTable theoryTable, labelsTable, trainedExamplesTable, objectsTable;
99  
  transient JTabbedPane tabs;
100  
  transient SingleComponentPanel scpPredictions;
101  
  S labelForDeepThought;
102  
  transient JComboBox cbLabelForDeepThought;
103  
  
104  
  // START CODE
105  
106  
  start {
107  
    thinkQ = dm_startQ("Thought Queue");
108  
    thinkQ.add(r {
109  
      // legacy + after deletion cleaning
110  
      setField(allLabels := asSyncTreeSet(msg2label_new.bKeys()));
111  
      updateLabelsByName();
112  
      
113  
      onNewLabel.add(lbl -> change());
114  
  
115  
      makeTheoriesAboutLabels();
116  
      makeTheoriesAboutFeaturesAndLabels();
117  
      
118  
      for (S field : fields(Msg))
119  
        featureExtractors.put(field, env -> getOpt(env.mainObject(), field));
120  
  
121  
      makeTextExtractors("text");
122  
  
123  
      callFAllOnAll(onNewLabel, allLabels);
124  
      onNewLabel.add(lbl -> setComboBoxItems(cbLabelForDeepThought, allLabels));
125  
      
126  
      msg2labelUpdated();
127  
      updatePredictions();
128  
      checkAllTheories();
129  
      //showRandomMsg();
130  
    });
131  
  }
132  
  
133  
  // THEORY MAKING
134  
135  
  void makeTheoriesAboutLabels {
136  
    // For any label X:
137  
    onNewLabel.add(lbl -> {
138  
      // test theory (for every M: M has label X)
139  
      addTheory(new Theory(BasicLogicRule(new MPTrue, new HasLabel(lbl))));
140  
      // test theory (for every M: M doesn't have label X)
141  
      addTheory(new Theory(BasicLogicRule(new MPTrue, new DoesntHaveLabel(lbl))));
142  
    });
143  
  }
144  
145  
  void makeTheoriesAboutFeaturesAndLabels {
146  
    // for every label X:
147  
    onNewLabel.add(lbl -> {
148  
      // For any feature F:
149  
      for (S feature : keys(featureExtractors))
150  
        // for every seen value V of F:
151  
        for (O value : possibleValuesOfFeatureRelatedToLabel(feature, lbl))
152  
          for (O rhs : ll(new HasLabel(lbl), new DoesntHaveLabel(lbl)))
153  
            // test theory (for every M: msg M's feature F has value V => msg has/doesn't have label x))
154  
            addTheory(new Theory(BasicLogicRule(
155  
              new FeatureValueIs(feature, value), rhs)));
156  
    });
157  
  }
158  
  
159  
  // THEORY MAKING (helper functions)
160  
161  
  Set possibleValuesOfFeature(S feature) {
162  
    if (isBoolField(Msg, feature))
163  
      ret litset(false, true);
164  
    ret litset();
165  
  }
166  
167  
  Set possibleValuesOfFeatureRelatedToLabel(S feature, S label) {
168  
    Set set = possibleValuesOfFeature(feature);
169  
    fOr (Msg msg : getMsgsRelatedToLabel(label))
170  
      set.add(getMsgFeature(msg, feature));
171  
    ret set;
172  
  }
173  
  
174  
  // CALCULATE FEATURES
175  
176  
  O getMsgFeature(Msg msg, S feature) {
177  
    ret msg2features.get(msg).get(feature);
178  
  }
179  
  
180  
  // returns AutoMap with no realized entries
181  
  Map<S, O> calcMsgFeatures(Msg msg) {
182  
    new Var<FeatureEnv<Msg>> env;
183  
    AutoMap<S, O> map = new AutoMap<S, O>(feature -> featureExtractors.get(feature).get(env!));
184  
    env.set(new FeatureEnv<Msg> {
185  
      Msg mainObject() { ret msg; }
186  
      O getFeature(S feature) { ret map.get(feature); }
187  
    });
188  
    ret map;    
189  
  }
190  
  
191  
  // GUI: Show messages
192  
193  
  void showMsgs(L<Msg> l) {
194  
    setField(shownMsgs := l);
195  
    setMsgs(l);
196  
    if (l(shownMsgs) == 1) {
197  
      Msg msg = first(shownMsgs);
198  
      setField(labelsForMsgText := or2(renderBoolMap(getMsgLabels(msg)), "-"));
199  
      setField(analysisText := joinWithEmptyLines(
200  
        "Trained Labels: " + labelsForMsgText,
201  
        "Features:\n" + formatColonProperties_quoteStringValues(
202  
msg2features.get(msg))
203  
      ));
204  
      setSCPComponent(scpPredictions,
205  
        scrollableStackWithSpacing(map(predictionsForMsg(msg), p -> {
206  
          S percent = iround(p.adjustedConfidence) + "%";
207  
          S neg = "not " + p.label;
208  
          Bool knownValue = msg2label_new.get(msg, p.label);
209  
          embedded S strong(S html) { ret b(html, style := "font-size: 18; color: #008000"); }
210  
          embedded JComponent makeButton(bool known, bool predicted, S label) {
211  
            S html = predicted ? jlabel_centerHTML(joinWithBR(
212  
              strong(htmlencode(label)), percent))
213  
              : label;
214  
            S toolTip = predicted ? "Predicted with " + percent + " confidence" + stringIf(!known, ". Click to confirm") 
215  
              : !known ? "Click to set this label for message" : "";
216  
            if (known) ret setTooltip(toolTip, jcenteredlabel(html));
217  
            JButton btn = setTooltip(toolTip, jbutton(html, rThread { sendInput2(label) }));
218  
            ret predicted ? btn : jfullcenter(btn);
219  
          }
220  
          
221  
          ret withSideMargin(jhgridWithSpacing(
222  
            makeButton(isTrue(knownValue), p.plus, p.label),
223  
            makeButton(isFalse(knownValue), !p.plus, neg)
224  
          ));
225  
        })));
226  
    } else setFields(analysisText := "", labelsForMsgText := "");
227  
  }
228  
229  
  void updatePredictions() {
230  
    showMsgs(shownMsgs);
231  
  }
232  
  
233  
  void showRandomMsg {
234  
    showMsgs(randomElementAsList(msgs));
235  
  }
236  
  
237  
  void showPrevMsg {
238  
    showMsgs(llNonNulls(prevInCyclicList(msgs, first(shownMsgs))));
239  
  }
240  
241  
  void showNextMsg {
242  
    showMsgs(llNonNulls(nextInCyclicList(msgs, first(shownMsgs))));
243  
  }
244  
245  
  // CALCULATE PREDICTIONS FOR MESSAGE
246  
247  
  L<Prediction> predictionsForMsg(Msg msg) {
248  
    // positive labels first, then "not"s. sort by score in each group
249  
    new L<Prediction> out;
250  
    for (Label label : values(labelsByName)) {
251  
      Theory t = label.bestTheory(), continue if null;
252  
      Bool lhs = evalTheoryLHS(t, msg), continue if null;
253  
      bool prediction = t.statement.rhs instanceof DoesntHaveLabel ? !lhs : lhs;
254  
      double conf = threeB1BScore(t.examples), adjusted = adjustConfidence(conf);
255  
      //if (adjusted < minAdjustedScoreToDisplay) continue;
256  
      out.add(new Prediction(label.name, prediction, adjusted));
257  
    }
258  
    ret sortedByCalculatedFieldDesc(out, p -> /*pair(p.plus,*/ p.adjustedConfidence/*)*/);
259  
  }
260  
261  
  // go from range 50-100 to 0-100 (looks better/more intuitive)
262  
  double adjustConfidence(double x) {
263  
    ret max(0, (x-50)*2);
264  
  }
265  
  
266  
  // rough reverse function of adjustConfidence
267  
  double unadjustConfidence(double x) {
268  
    ret x/2+50;
269  
  }
270  
  
271  
  // GUI: Enter labels
272  
  
273  
  void acceptPrediction(Prediction p) {
274  
    if (p != null) sendInput2(p.predictedLabel());
275  
  }
276  
277  
  void rejectPrediction(Prediction p) {
278  
    if (p != null) sendInput2(cloneWithFlippedBoolField plus(p).predictedLabel());
279  
  }
280  
281  
  @Override
282  
  void sendInput2(S s) {
283  
    // treat input as a label
284  
    if (l(shownMsgs) == 1) {
285  
      Msg shown = first(shownMsgs);
286  
      new Matches m;
287  
      if "not ..." {
288  
        S label = cleanLabel(m.rest());
289  
        doubleKeyedMapPutVerbose(+msg2label_new, shown, label, false);
290  
        msg2labelUpdated(label);
291  
        if (autoNext) showRandomMsg();
292  
      } else {
293  
        S label = cleanLabel(s);
294  
        doubleKeyedMapPutVerbose(+msg2label_new, shown, label, true);
295  
        msg2labelUpdated(label);
296  
        if (autoNext) showRandomMsg();
297  
      }
298  
      change();
299  
    }
300  
  }
301  
  
302  
  // MESSAGE LABEL HANDLING
303  
304  
  Map<S, Bool> getMsgLabels(Msg msg) {
305  
    ret msg2label_new.getA(msg);
306  
  }
307  
  
308  
  Set<Msg> getMsgsRelatedToLabel(S label) { ret msg2label_new.asForB(label); }
309  
310  
  void msg2labelUpdated(S label) {
311  
    for (Theory t : cloneList(labelByName(label).bestTheories))
312  
      checkTheory(t);
313  
    msg2labelUpdated();
314  
  }
315  
316  
  void msg2labelUpdated() {
317  
    callFAllOnAll(onNewLabel, addAll_returnNew(allLabels, msg2label_new.bKeys()));
318  
    updateTrainedExamplesTable();
319  
  }
320  
  
321  
  // QUERY: get all labels + best theory each
322  
  
323  
  Map<S, Theory> labelsToBestTheoryMap() {
324  
    Map<S, L<Theory>> map = multiMapToMap(multiMapIndex targetLabelOfTheory(theories));
325  
    ret mapValues(map, theories -> highestBy theoryScore(theories));
326  
  }
327  
  
328  
  Map<Msg, Bool> examplesForLabel(S label) {
329  
    ret msg2label_new.getB(label);
330  
  }
331  
332  
  // GUI: Main layout
333  
334  
  visual
335  
    withCenteredButtons(super,
336  
      "<", rInThinkQ(r showPrevMsg),
337  
      "Show random msg", rInThinkQ(r showRandomMsg),
338  
      ">", rInThinkQ(r showNextMsg),
339  
      jPopDownButton_noText(flattenObjectArray(
340  
        "Check theories", rInThinkQ(r checkAllTheories),
341  
        "Forget bad theories", rInThinkQ(r { forgetBadTheories(0) }),
342  
        "Forget all theories", rInThinkQ(r clearTheories),
343  
        "Update predictions", rInThinkQ(r updatePredictions),
344  
        dm_importAndExportAllDataMenuItems())));
345  
346  
  JComponent mainPart() {
347  
    tablePopupMenuItemsThreaded_top(labelsTable = sexyTable(),
348  
      "Copy examples to clipboard", rEnter {
349  
        copyTextToClipboard_lineCountInfoBox(collectAsLines text(keysWithValueTrue(examplesForLabel((S) selectedTableCell(labelsTable, "Label")))))
350  
      },
351  
      "Copy counterexamples to clipboard", rEnter {
352  
        copyTextToClipboard_lineCountInfoBox(collectAsLines text(keysWithValueFalse(examplesForLabel((S) selectedTableCell(labelsTable, "Label")))))
353  
      });
354  
    ret jhsplit(jvsplit(
355  
      jCenteredSection("Focused Message",
356  
        centerAndSouthWithMargin(super.mainPart(),
357  
        jCenteredSection("Labels assigned to message", dm_centeredLabel labelsForMsgText()))),
358  
      //jhsplit(
359  
        jCenteredSection("Predictions for message (green)", scpPredictions = singleComponentPanel()),
360  
        /*jCenteredSection("Deep Thought", northAndCenterWithMargin(
361  
          withLabel("Think about label:", cbLabelForDeepThought = dm_comboBox labelForDeepThought(allLabels)),
362  
          jcenteredlabel("TODO")))
363  
      )*/),
364  
      with(r updateTabs, tabs = jtabs(
365  
        "", with(r updateObjectsTable, withRightAlignedButtons(
366  
          tablePopupMenuItemsThreaded(
367  
            onDoubleClickOrEnter(rThread showSelectedObject,
368  
              objectsTable = sexyTable()),
369  
            "Delete", r deleteSelectedMessages),
370  
          "Import messages...", rThreadEnter importMsgs)),
371  
        "", with(r updateLabelsTable, labelsTable),
372  
        "", with(r updateTheoryTable, tableWithSearcher2_returnPanel(theoryTable = sexyTable())),
373  
        "", with(r updateTrainedExamplesTable, tableWithSearcher2_returnPanel(trainedExamplesTable = sexyTable()))
374  
      )));
375  
  }
376  
  
377  
  // GUI: Update tables & tabs
378  
379  
  void updateTrainedExamplesTable {
380  
    dataToTable_uneditable(trainedExamplesTable, map(msg2label_new.map1, (msg, map) ->
381  
      litorderedmap(
382  
        "Message" := (msg.fromUser ? "User" : "Bot") + ": " + msg.text,
383  
        "Labels" := renderBoolMap(map))));
384  
  }
385  
386  
  void updateTabs {
387  
    setTabTitles(tabs,
388  
      firstLetterToUpper(nMessages(msgs)),
389  
      firstLetterToUpper(nLabels(labelsByName)),
390  
      firstLetterToUpper(nTheories(theories)),
391  
      n2(msg2label_new.aKeys(), "Trained Example"));
392  
  }
393  
394  
  void updateTheoryTable {
395  
    L<Theory> sorted = sortedByCalculatedFieldDesc theoryScore(theories);
396  
    dataToTable_uneditable(theoryTable, map(sorted, t -> litorderedmap(
397  
      "Score" := renderTheoryScore(t),
398  
      "Theory" := str(t))));
399  
  }
400  
401  
  void updateObjectsTable enter {
402  
    dataToTable_uneditable_ifHasTable(objectsTable, map(msgs, msg ->
403  
      litorderedmap("Text" := msg.text)
404  
    ));
405  
  }
406  
407  
  void updateLabelsTable enter {
408  
    L<Label> sorted = sortedByCalculatedFieldDesc(values(labelsByName), l -> l.score());
409  
    dataToTable_uneditable_ifHasTable(labelsTable, map(sorted, label -> {
410  
      Cl<Theory> bestTheories = label.bestTheories.tiedForFirst();
411  
      Map<Msg, Bool> examples = examplesForLabel(label.name);
412  
      ret litorderedmap(
413  
        "Label" := label.name,
414  
        "Examples/Counterexamples" := countKeysWithValue(true, examples) + "/" + countKeysWithValue(false, examples),
415  
        "Prediction Confidence" := renderTheoryScore(first(bestTheories)),
416  
        "Best Theory" := empty(bestTheories) ? "" :
417  
          (l(bestTheories) > 1 ? "[+" + (l(bestTheories)-1) + "] " : "") +  first(bestTheories));
418  
    }));
419  
  }
420  
  
421  
  void theoriesChanged {
422  
    updateTheoryTable();
423  
    updateLabelsTable();
424  
    updateTabs();
425  
    updatePredictions();
426  
    change();
427  
  }
428  
429  
  // THEORY SCORING
430  
  
431  
  S renderTheoryScore(Theory t) {
432  
    //ret renderPosNegCounts(t.examples);
433  
    ret t == null || t.examples.isEmpty() ? "" : iround(theoryScore(t)) + "%"
434  
      + " / " + renderPosNegScore2(t.examples);
435  
  }
436  
437  
  // adjusted + 3b1b
438  
  double theoryScore(Theory t) {
439  
    ret t == null ? -100 : adjustConfidence(threeB1BScore(t.examples));
440  
  }
441  
  
442  
  // QUEUE HELPER
443  
444  
  Runnable rInThinkQ(Runnable r) { ret rInQ(thinkQ, r); }
445  
  
446  
  // ADD + REMOVE + CLEAN UP THEORIES
447  
448  
  void addTheory(Theory theory) {
449  
    if (theories.add(theory)) {
450  
      addTheoryToCollectors(theory);
451  
      theoriesChanged();
452  
    }
453  
  }
454  
455  
  void clearTheories { theories.clear(); theoriesChanged(); }
456  
  
457  
  // theories with exaclty minScore will go too
458  
  void forgetBadTheories(double minScore) {
459  
    if (removeElementsThat(theories, t -> theoryScore(t) <= minScore))
460  
      theoriesChanged();
461  
  }
462  
  
463  
  // CHECK PROPOSITIONS + THEORIES
464  
465  
  Bool checkMsgProp(O prop, Msg msg) {
466  
    if (prop cast And) ret checkMsgProp(prop.a, msg) && checkMsgProp(prop.b, msg);
467  
    if (prop cast Not) ret not(checkMsgProp(prop.a, msg));
468  
    ret ((MsgProp) prop).check(msg);
469  
  }
470  
471  
  Bool evalTheoryLHS(Theory theory, Msg msg) {
472  
    ret theory == null ? null
473  
      : checkMsgProp(theory.statement.lhs, msg);
474  
  }
475  
476  
  Bool testTheoryOnMsg(Theory theory, Msg msg) {
477  
    Bool lhs = evalTheoryLHS(theory, msg);
478  
    Bool rhs = checkMsgProp(theory.statement.rhs, msg);
479  
    if (lhs == null || rhs == null) null;
480  
    if (bidiMode)
481  
      ret eq(lhs, rhs);
482  
    else
483  
      ret isTrue(rhs) || isFalse(lhs);
484  
  }
485  
486  
  void checkAllTheories {
487  
    for (Theory theory : theories)
488  
      checkTheory_noTrigger(theory);
489  
    theoriesChanged();
490  
  }
491  
492  
  void checkTheory(Theory theory) {
493  
    checkTheory_noTrigger(theory);
494  
    theoriesChanged();
495  
  }
496  
497  
  void checkTheory_noTrigger(Theory theory) {
498  
    new PosNeg<Msg> pn;
499  
    for (Msg msg : msgs)
500  
      pn.add(msg, testTheoryOnMsg(theory, msg));
501  
    if (!eq(theory.examples, pn)) {
502  
      removeTheoryFromCollectors(theory);
503  
      theory.examples = pn;
504  
      addTheoryToCollectors(theory);
505  
      change();
506  
    }
507  
  }
508  
  
509  
  S targetLabelOfTheory(Theory theory) {
510  
    O o = theory.statement.rhs;
511  
    if (o cast HasLabel) ret o.label;
512  
    if (o cast DoesntHaveLabel) ret o.label;
513  
    null;
514  
  }
515  
516  
  // CANONICALIZE LABELS
517  
518  
  S cleanLabel(S label) { ret upper(label); }
519  
  
520  
  // THEORY + LABEL UPDATES
521  
  
522  
  void addTheoryToCollectors(Theory theory) {
523  
    S lbl = targetLabelOfTheory(theory);
524  
    if (lbl != null)
525  
      labelByName(lbl).bestTheories.add(theory);
526  
  }
527  
528  
  void removeTheoryFromCollectors(Theory theory) {
529  
    S lbl = targetLabelOfTheory(theory);
530  
    if (lbl != null)
531  
      labelByName(lbl).bestTheories.remove(theory);
532  
  }
533  
534  
  Label labelByName(S name) {
535  
    ret getOrCreate(labelsByName, name, () -> new Label(name));
536  
  }
537  
538  
  void updateLabelsByName() {
539  
    for (S lbl : allLabels)
540  
      labelByName(lbl);
541  
    for (Theory t : theories)
542  
      addTheoryToCollectors(t);
543  
  }
544  
545  
  // MAKE FEATURE EXTRACTORS
546  
547  
  void makeTextExtractors(S textFeature) {
548  
    for (WithName<IF1<S, O>> f : textExtractors()) {
549  
      IF1<S, O> theFunction = f!;
550  
      featureExtractors.put(f.name, env -> theFunction.get((S) env.getFeature(textFeature)));
551  
    }
552  
  }
553  
554  
  L<WithName<IF1<S, O>>> textExtractors() {
555  
    new L<WithName<IF1<S, O>>> l;
556  
    l.add(WithName<>("number of words", lambda1 numberOfWords));
557  
    l.add(WithName<>("number of characters", lambda1 l));
558  
    for (char c : characters("\"', .-_"))
559  
      l.add(WithName<>("contains " + quote(c), s -> contains(s, c)));
560  
    /*for (S word : concatAsCISet(lambdaMap words(collect text(msgs))))
561  
      l.add(WithName<>("contains word " + quote(word), s -> containsWord(s, word)));*/
562  
    ret l;
563  
  }
564  
  
565  
  // GUI: Import messages dialog, warn on delete, other stuff
566  
567  
  void importMsgs {
568  
    inputMultiLineText("Messages to import (one per line)", voidfunc(S text) {
569  
      Cl<S> toImport = listMinusSet(asOrderedSet(tlft(text)), collectAsSet text(msgs));
570  
      if (msgs == null) msgs = ll();
571  
      for (S line : toImport)
572  
        msgs.add(new Msg(true, line));
573  
      change();
574  
      infoBox(nMessages(toImport) + " imported");
575  
      updateObjectsTable();
576  
      showRandomMsg();
577  
    });
578  
  }
579  
  
580  
  bool warnOnDelete() { true; }
581  
  
582  
  void showSelectedObject enter {
583  
    showMsgs(llNotNulls(get(msgs, selectedRow(objectsTable))));
584  
  }
585  
  
586  
  void deleteSelectedMessages {
587  
    Set<Msg> toDelete = asSet(getMulti(msgs, selectedRows(objectsTable)));
588  
    removeFromCollection(msgs, toDelete);
589  
    removeAll(msg2features, toDelete);
590  
    msg2label_new.removeAllA(toDelete);
591  
    change();
592  
    updateObjectsTable();
593  
    showRandomMsg();
594  
  }
595  
  
596  
  // DEEP THOUGHT (make more complex theories for label)
597  
  
598  
  void deepThought(S label) {
599  
  }
600  
}

Author comment

Began life as a copy of #1028063

download  show line numbers  debug dex  old transpilations   

Travelled to 7 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt, xrpafgyirdlv

No comments. add comment

Snippet ID: #1028066
Snippet name: Auto Classifier v5 [learning message classifier]
Eternal ID of this version: #1028066/30
Text MD5: 28da243219e7f859a308c41d5f12514d
Transpilation MD5: d994e645303cfdfd02142b8f06886da7
Author: stefan
Category: javax / a.i.
Type: JavaX source code (Dynamic Module)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2020-06-07 19:27:39
Source code size: 19856 bytes / 600 lines
Pitched / IR pitched: No / No
Views / Downloads: 209 / 3366
Version history: 29 change(s)
Referenced in: [show references]