abstract sclass DynAttractorBot > DynPrintLog { S input, dialogText; bool voiceMode; AttractorBot bot; transient L onBotSaid = synchroList(); // L> transient bool activateOnOutput = true; bool persistBot; transient JTabbedPane tabs; void submitInput(S input) { setField(+input); submitInput(); } void submitInput { lock lock; setField(input := trim(input)); addToDialog("User: " + input); S s = input; if "new dialogue|new dialog" startDialog(); else if (bot != null) bot.addInput(input); } visual tabs = jtabs("Dialog" := northCenterAndSouthWithMargins( rightAlignedButtons( dm_fieldCheckBox('voiceMode), "New dialog", rThread startDialog, "Clear window", rThread clearDialogText), wordWrapTextArea(dm_textArea_scrollDown_readOnly('dialogText)), dm_textFieldAndSubmit_q('input, 'submitInput, focusOnShow := true)), "Log" := super); void runBot(AttractorBot bot) { setField(+bot); runBot(); } void addToDialog(S s) { setField(dialogText := appendWithNewLine(dialogText, print(s))); } void runBot { bot.say = voidfunc(S s) { addToDialog("Bot: " + s); pcallFAll(onBotSaid, s); vmBus_send aBotSaid(me(), s); if (voiceMode) { if (activateOnOutput) dm_activateOSAndModule(); dm_say(s); } }; thread "Bot" { bot.run_public(); print("\n[end]"); } } void clearDialogText { setField(dialogText := ""); } abstract AttractorBot makeBot(); void makeBotIfNotThere { if (bot == null) setField(bot := makeBot()); } void startDialog { clearDialogText(); makeBotIfNotThere(); runBot(bot); } start { logModuleOutput(); dontPersist('bot); dm_onTopInput_q(voidfunc(S s) { if (!voiceMode) ret; //dm_activateOSAndModule(); submitInput(s); }); startDialog(); } void persistBot { doPersist('bot); } }