Erstellen Sie einen Chatbot für die Stack Exchange-Chatrooms

39

Die Herausforderung

Ziel dieser Herausforderung ist es, einen Chatbot zu erstellen, der in den Chatrooms von Stack Exchange ausgeführt werden kann. Ihr Bot muss in der Lage sein, zu erkennen, wann bestimmte Befehle von einem Benutzer gesendet wurden, und darauf zu antworten. Dies ist die Liste der Befehle und was Ihr Bot tun sollte:

  • !!newest: gibt den Titel (kein Link, aber den Titel) der neuesten Frage auf dieser Seite aus (codegolf.SE).
  • !!metanewest: gibt den Titel der neuesten Frage aus, die auf der Meta-Site (meta.codegolf.SE) veröffentlicht wurde.
  • !!questioncount: gibt die aktuelle Anzahl der Fragen aus.
  • !!metaquestioncount: gibt die aktuelle Anzahl der Fragen auf der Meta-Site aus.
  • !!tag tagname: gibt den Tag-Auszug (die Kurzbeschreibung) des Tags aus, der als erster Parameter angegeben wurde.
  • !!metatag tagname: wie oben, aber für die Meta-Site.
  • !!featured: Gibt die Anzahl der Fragen aus, für die derzeit ein Kopfgeld gezahlt wird.
  • !!metafeatured: Gibt die Anzahl der Fragen mit dem [featured] -Tag auf Meta aus.

Regeln

  1. Sie sollten ein vollständiges Programm schreiben, kein Snippet oder eine Funktion.
  2. Falls erforderlich, können Sie Benutzername und Kennwort als Eingabe anfordern (Eingabeaufforderung, STDIN, Befehlszeilenargumente). Dies ist erforderlich, wenn Sie beispielsweise Python oder Ruby verwenden. Wenn Sie jedoch JavaScript verwenden und das Skript auf der Chatroom-Seite selbst ausführen, ist dies nicht erforderlich.
  3. Sie dürfen externe Bibliotheken verwenden, um Dinge wie WebSockets zu erledigen. Diese Bibliotheken müssen nicht für Ihre Zeichenzahl zählen.
  4. Sie können einen externen Chat-Wrapper verwenden (müssen dies aber nicht, es wird empfohlen, einen eigenen zu schreiben), und dieser muss dann für die Anzahl der Zeichen zählen. Sie dürfen auch den Code des Wrappers nicht ändern. Wenn Sie es verwenden, verwenden Sie es ohne Änderungen und alle Zeichen müssen gezählt werden (das ist eine Strafe, wenn Sie nicht Ihren eigenen Wrapper schreiben).

    Nur der Code des Wrappers selbst muss zählen. Wenn es andere Dateien wie Beispiele gibt, müssen diese nicht gezählt werden.

  5. Keine Verwendung von URL-Kürzern oder anderen Möglichkeiten, um URLs zu verkürzen: Die Herausforderung besteht darin, einen Chatbot zu spielen, nicht eine URL.
  6. Keine Webanfragen, außer denjenigen, die zum Chatten und Abrufen der für die Beantwortung der Befehle erforderlichen Informationen erforderlich sind.
  7. Die Verwendung der Standard "Lücken" ist nicht gestattet.
  8. Wenn jemand Beiträge ein Befehl, müssen Sie reagieren mit einer Chat - Nachricht dieses Format: @user response. Wenn ich also den Befehl schreibe !!featuredund es gibt 5 vorgestellte Fragen, sollte Ihr Bot posten @ProgramFOX 5.
  9. Wenn ich Ihren Bot teste, starte ich ihn von meinem Chatbot-Konto aus und starte ihn in diesem Chatroom . Ich werde die Bots in diesem Raum immer testen, daher ist es nicht erforderlich, eine Raum-ID als Eingabe anzugeben. Es ist immer 14697. Diese ID wird nicht als Eingabe angegeben, sie sollte fest codiert sein.
  10. Wird der Befehl nicht gefunden, wird ausgegeben @user The command [command] does not exist. Ersetzen Sie [command]durch den Namen des nicht vorhandenen Befehls. Wenn dem Befehl Argumente bereitgestellt werden, geben Sie nicht die Argumente, sondern nur den Befehlsnamen aus.
  11. Wenn ein Befehl zu viele Argumente enthält, ignorieren Sie die nicht erforderlichen Argumente.
  12. Wenn ein Befehl nicht genügend Argumente enthält, wird ausgegeben @user You have not provided enough arguments
  13. Das System verhindert, dass doppelte Nachrichten innerhalb eines kurzen Zeitraums gebucht werden. Wenn Sie Ihren Bot testen, führe ich niemals zwei Befehle aus, die nacheinander die gleiche Ausgabe liefern (was bedeutet, dass Sie kein System implementieren müssen, das Nachrichten unterscheidet, wenn sie Duplikate sind, indem Sie beispielsweise einen Punkt hinzufügen).
  14. Das System verhindert, dass zu viele Nachrichten innerhalb eines kurzen Zeitraums gesendet werden. Daher sende ich beim Testen niemals zu viele Befehle innerhalb eines kurzen Zeitraums. Das bedeutet, dass Ihr Bot sich nicht darum kümmern muss (indem er einige Zeit wartet) zum Beispiel vor dem Posten).
  15. Dies ist , das Programm mit der geringsten Anzahl von Bytes gewinnt.

Loslegen

Hier finden Sie einige Informationen, um mit dem Schreiben Ihres Bots zu beginnen. Sie müssen dies nicht verwenden, aber es kann eine Anleitung sein.

  • Um sich anzumelden, melden Sie sich zuerst bei einem OpenID-Anbieter an. Dies ist immer die Stack Exchange OpenID ( https://openid.stackexchange.com). Das Anmeldeformular befindet sich unter https://openid.stackexchange.com/account/loginund gibt dort den Benutzernamen und das Passwort an.
  • Dann melden Sie sich an stackexchange.com. Das Anmeldeformular befindet sich unter https://stackexchange.com/users/login. Wählen Sie Stack Exchange als OpenID-Provider.
  • Danach melde dich an, um zu chatten. Das Anmeldeformular dafür befindet sich unter http://stackexchange.com/users/chat-login. Wählen Sie Stack Exchange als OpenID-Provider.
  • Dann müssen Sie Ihre bekommen fkey. Gehen Sie dazu zu http://chat.stackexchange.com/chats/join/favoriteund holen Sie sich das fkeyvon einem versteckten Eingabefeld.
  • Senden Sie zum Posten einer Nachricht eine Anfrage an http://chat.stackexchange.com/chats/14697/messages/newund geben Sie zwei POST-Parameter an: einen textParameter mit dem Nachrichtentext und einen fkeyParameter mit dem fkey.
  • Um zu sehen, wann eine neue Nachricht veröffentlicht wird, können Sie WebSockets verwenden (müssen Sie aber nicht, können Sie auch etwas anderes verwenden, wenn es kürzer ist). Bitte lesen Sie diese Meta Stack Exchange-Antwort :

    Plaudern

    (wss://chat.sockets.stackexchange.com/events/<roomnumber>/<somehash>?l=<timethingy>)

    Der Hash kann durch POSTING der Raum-ID und der F-Taste zu abgerufen werden http://chat.stackexchange.com/ws-auth

    Der timethingy ist der Zeitschlüssel des von zurückgegebenen json /chats/<roomno>/events.

    Die Ereignis-ID beim Versenden einer Nachricht lautet 1.

  • Es ist hilfreich, sich die vorhandenen Chat-Wrapper wie StackExchange -Chatty von Doorknob und ChatExchange von Manishearth anzusehen , um zu sehen, wie dies genau funktioniert.
ProgramFOX
quelle
3
Als ich den Titel sah, dachte ich sofort "ah, ProgramFOX".
Siehe auch
Ich hatte gehofft metafeatured, dass es viele Fragen zu Meta geben würde, aber ... danke :-)
John Dvorak
@ JanDvorak Metas pro Site haben keine Kopfgelder, daher kann ich das nicht verwenden. Als ich diese Herausforderung schrieb, vergaß ich, dass Meta ein [empfohlenes] Tag hatte. Vielen Dank für Ihren Vorschlag!
ProgramFOX
Was ich getan habe, um zu sehen, ob eine neue Nachricht gepostet wurde, war alle 2 Sekunden per JS zu überprüfen, ob die letzte Nachricht nicht von mir stammt (letzter Punkt in der Klasse)
Cilan
Wir haben bereits eine hier
Mr. Alien

Antworten:

14

JavaScript + jQuery, 1362 - 1258 Byte

Golfen mit einem Minifier:

$(function(){function e(){function e(e,t){$("#input").val("@"+$(e).parents(".user-container").find(".username").eq(0).text()+" "+t),$("#sayit-button").click()}var i,a=$(t),s=a.map(function(e,t){return t.id}),r=s.slice(-1)[0]
n!=r&&(i=a.slice($.inArray(n,s)+1),n=r,i.map(function(t,n){var i,a,s,r,o,u,c,f=n.textContent.match(/!!(\S+)(?:\s+(\S+))?/)
if(f){switch(i=f[1],a=f[2],s="codegolf",0==i.indexOf("meta")&&(s="meta."+s,i=i.slice(4)),r="?site="+s,c=0,i){case"newest":o=["questions","&order=desc&sort=creation"],u=function(e){return e.items[0].title}
break
case"questioncount":o=["info",""],u=function(e){return e.items[0].total_questions}
break
case"tag":if(!a){c=1
break}o=["tags/"+a+"/wikis",""],u=function(e){return 0==e.items.length?"Tag not found":e.items[0].excerpt}
break
case"featured":o=0==s.indexOf("meta.")?["questions","&tagged=featured"]:["questions/featured",""],u=function(e){var t=e.items.length
return(e.items.has_more?"more than ":"")+t}}c?e(n,"You have not provided enough arguments"):o?$.get("http://api.stackexchange.com/2.2/"+o[0]+r+o[1],function(t){e(n,u(t))}):e(n,"The command "+i+" does not exist")}}))}var t="[id^=message-]",n=$(t).eq(-1).attr("id")
new MutationObserver(e).observe($("#chat").get(0),{childList:!0,subtree:!0})})

Sie müssen das Skript direkt im Browser ausführen (unter Verwendung der jQuery-Funktionen von Stack Exchange):

  1. Öffnen Sie http://chat.stackexchange.com/rooms/14697/chatbot-challenge-on-programming-puzzles-code-golf
  2. Fügen Sie den obigen Code in die Konsole ein
  3. Geben Sie einige Befehle in den Chat ein

Es könnte viel mehr Golf gespielt werden, aber es könnte nicht stören.


Nicht golfen:

$(function() {
    var sel = '[id^=message-]';
    var latestMessage = $(sel).eq(-1).attr('id');
    function update() {
        var messages = $(sel);
        var ids = messages.map(function(i, x) { return x.id; });
        var newest = ids.slice(-1)[0];
        if(latestMessage == newest) {
            return;
        }
        var newMessages = messages.slice($.inArray(latestMessage, ids) + 1);
        latestMessage = newest;
        newMessages.map(function(i, x) {
            var m = x.textContent.match(/!!(\S+)(?:\s+(\S+))?/);
            if(!m) {
                return;
            }
            var c = m[1];
            var a = m[2];
            var s = 'codegolf';
            if(c.indexOf('meta') == 0) {
                s = 'meta.' + s;
                c = c.slice(4);
            }
            var site = '?site=' + s;
            var url;
            var extractor;
            var too_few_args = 0;
            switch(c) {
                case 'newest':
                    var url = ['questions', '&order=desc&sort=creation'];
                    extractor = function(data) {
                        return data.items[0].title;
                    };
                    break;
                case 'questioncount':
                    url = ['info', ''];
                    extractor = function(data) {
                        return data.items[0].total_questions;
                    };
                    break;
                case 'tag':
                    if(!a) {
                        too_few_args = 1;
                        break;
                    }
                    url = ['tags/' + a + '/wikis', ''];
                    extractor = function(data) {
                        if(data.items.length == 0) {
                            return 'Tag not found';
                        }
                        return data.items[0].excerpt;
                    };
                    break;
                case 'featured':
                    url = s.indexOf('meta.') == 0? ['questions', '&tagged=featured']: ['questions/featured', ''];
                    extractor = function(data) {
                        var l = data.items.length;
                        return (data.items.has_more? 'more than ': '') + l;
                    }
                    break;
            }
            if(too_few_args) {
                write(x, 'You have not provided enough arguments');
            } else if(!url) {
                write(x, 'The command ' + c + ' does not exist');
            } else {
                $.get('http://api.stackexchange.com/2.2/' + url[0] + site + url[1], function(data) {
                    write(x, extractor(data));
                });
            }
        });

        function write(x, m) {
            $('#input').val('@' + $(x).parents('.user-container').find('.username').eq(0).text() + ' ' + m);
            $('#sayit-button').click();
        }
    }
    new MutationObserver(update).observe($('#chat').get(0), {childList: true, subtree: true});
});
Tyilo
quelle
Schön, danke, dass du hier eine Antwort postest! Ich werde jetzt die Tests im Raum durchführen. Wie auch immer, ich glaube , Sie einige Zeichen speichern können mehr Ein-Buchstaben - Variablen und die Vermeidung von updateund latestMessage.
ProgramFOX
Toll! Sie haben alle Tests bestanden . Das einzig Seltsame, das mir aufgefallen ist, ist, dass Ihr Bot eine andere Anzahl von Fragen zurückgegeben hat als auf der Startseite. Ich habe jedoch festgestellt, dass die API diese Nummer zurückgegeben hat. Deshalb habe ich dies auf Meta gemeldet und den Testfall als korrekt markiert. Gut gemacht! +1
ProgramFOX
Ich habe gesehen, dass du den Bot kürzer gemacht hast. Nett! :) Ich habe es erneut getestet und du hast immer noch alle Tests bestanden.
ProgramFOX
Ziemlich spät, aber ich fand nur eine Ein-char Verbesserung: Sie können ersetzen 0==e.items.lengthmit , 1>e.items.lengthda die Länge nie unter Null gehen.
ProgramFOX