Creare un chatbot per le chat room di Stack Exchange


39

La sfida

L'obiettivo di questa sfida è creare un chatbot che possa essere eseguito nelle chat room di Stack Exchange. Il tuo bot deve essere in grado di rilevare quando un utente inserisce comandi specifici e rispondere ad esso. Questo è l'elenco dei comandi e cosa dovrebbe fare il tuo bot:

  • !!newest: visualizza il titolo (nessun link, ma il titolo) dell'ultima domanda pubblicata su questo sito (codegolf.SE).
  • !!metanewest: visualizza il titolo dell'ultima domanda pubblicata sul meta sito (meta.codegolf.SE).
  • !!questioncount: visualizza il conteggio delle domande corrente.
  • !!metaquestioncount: genera il conteggio delle domande corrente sul meta sito.
  • !!tag tagname: genera l'output del tag (la breve descrizione) del tag che viene fornito come primo parametro.
  • !!metatag tagname: come sopra, ma per il meta sito.
  • !!featured: genera il conteggio delle domande che attualmente hanno una taglia.
  • !!metafeatured: genera il conteggio delle domande che hanno il tag [in evidenza] su Meta.

Regole

  1. Dovresti scrivere un programma completo, non uno snippet o una funzione.
  2. Nel caso sia necessario, è possibile richiedere nome utente e password come input (richiesta di input, STDIN, argomenti della riga di comando). Ciò sarà necessario se si utilizza, ad esempio, Python o Ruby, ma non sarà necessario se si utilizza JavaScript ed si esegue lo script nella stessa pagina della chat room.
  3. Puoi usare librerie esterne per fare cose come WebSocket. Queste librerie non devono contare per il conteggio dei personaggi.
  4. È possibile utilizzare una chat involucro esterno (ma non è necessario, scrivere il proprio è incoraggiato), e quindi che deve contare per il conteggio dei caratteri. Inoltre, non è consentito modificare il codice del wrapper. Se lo usi, lo usi senza modifiche e tutti i personaggi devono essere contati (è una penalità per non aver scritto il tuo wrapper).

    Deve contare solo il codice del wrapper stesso. Se ci sono altri file come esempi, questi non devono contare.

  5. Nessun uso di accorciatori di URL o altri modi per accorciare gli URL: la sfida è giocare a golf un chatbot, non giocare a golf un URL.
  6. Nessuna richiesta web, ad eccezione di quelle necessarie per chattare e ottenere le informazioni necessarie per rispondere ai comandi.
  7. L'uso delle "scappatoie" standard non è consentito.
  8. Se qualcuno pubblica un comando, è necessario rispondere con un messaggio di chat di questo formato: @user response. Quindi, se scrivo il comando !!featurede ci sono 5 domande in primo piano, il tuo bot dovrebbe pubblicare @ProgramFOX 5.
  9. Se collaudo il tuo bot, lo eseguirò dal mio account chatbot e lo eseguirò in questa chatroom . Metterò sempre alla prova i robot in quella stanza, quindi non è necessario fornire l'ID stanza come input, sarà sempre 14697. Questo ID non verrà fornito come input, dovrebbe essere codificato.
  10. Se il comando non viene trovato, output @user The command [command] does not exist. Sostituisci [command]con il nome del comando inesistente. Se vengono forniti argomenti al comando, non generare gli argomenti, ma solo il nome del comando.
  11. Se un comando ha molti argomenti, ignora gli argomenti che non sono necessari.
  12. Se un comando non ha argomenti sufficienti, output @user You have not provided enough arguments
  13. Il sistema impedisce che messaggi duplicati vengano pubblicati in un breve intervallo di tempo. Quindi, quando collaudo il tuo bot, non eseguirò mai due comandi che danno lo stesso output in successione (il che significa che non devi implementare un sistema che rende i messaggi diversi se sono duplicati, aggiungendo un punto per esempio).
  14. Il sistema impedisce che troppi messaggi vengano pubblicati entro un breve intervallo di tempo, quindi durante il test non invierò mai troppi comandi in un breve intervallo di tempo, il che significa che il tuo bot non deve occuparsene (aspettando un po 'di tempo prima di pubblicare, per esempio).
  15. Questo è , vince il programma con il minor numero di byte.

Iniziare

Ecco alcune informazioni per iniziare a scrivere il tuo bot. Non è necessario utilizzare questo, ma può essere una guida.

  • Per accedere, accedi prima a un provider OpenID. Questo sarà sempre Stack Exchange OpenID ( https://openid.stackexchange.com). Il modulo di accesso si trova all'indirizzo https://openid.stackexchange.com/account/logine fornire nome utente e password lì.
  • Quindi, accedi a stackexchange.com. Il modulo di accesso si trova all'indirizzo https://stackexchange.com/users/login. Scegli Stack Exchange come provider OpenID.
  • Dopo averlo fatto, accedi per chattare. Il modulo di accesso per questo si trova in http://stackexchange.com/users/chat-login. Scegli Stack Exchange come provider OpenID.
  • Quindi devi ottenere il tuo fkey. Per questo, vai a http://chat.stackexchange.com/chats/join/favoritee ottieni il fkeyda un campo di input nascosto.
  • Per inviare un messaggio, inviare una richiesta a http://chat.stackexchange.com/chats/14697/messages/newe fornire due parametri POST: un textparametro contenente il testo del messaggio e un fkeyparametro contenente il fkey.
  • Per vedere quando viene pubblicato un nuovo messaggio, puoi usare WebSocket (ma non è necessario, sentiti libero di usare qualcos'altro se è più corto). Si prega di vedere questa risposta scambio Meta Stack :

    Chiacchierare

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

    L'hash può essere recuperato POSTANDO l'id della stanza e toccando http://chat.stackexchange.com/ws-auth

    Il segnatempo è la chiave del tempo del json restituito /chats/<roomno>/events.

    L'ID evento al momento della pubblicazione di un messaggio è 1.

  • È utile esaminare i wrapper di chat esistenti, come StackExchange-Chatty di Doorknob e ChatExchange di Manishearth , per vedere come funziona esattamente.

3
Nel momento in cui ho visto il titolo, ho pensato subito "ah, ProgramFOX".
Seequ,

Speravo metafeaturedche significasse domande abbondanti su meta, ma ... grazie :-)
John Dvorak,

@JanDvorak I metas per sito non hanno taglie, quindi non posso usarlo. Quando ho scritto questa sfida, ho dimenticato che Meta aveva un tag [in primo piano], quindi grazie per il tuo suggerimento!
ProgramFOX

Quello che ho fatto per vedere se veniva pubblicato un nuovo messaggio era controllare ogni 2 secondi tramite JS se l'ultimo messaggio non era da me (ultimo elemento in classe)
Cilan

Ne abbiamo già uno qui
Mr. Alien,

Risposte:


14

JavaScript + jQuery, 1362 1258 byte

Giocato a golf usando un minificatore:

$(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})})

Devi eseguire lo script direttamente nel browser (usando i lavori jQuery di Stack Exchange):

  1. Apri http://chat.stackexchange.com/rooms/14697/chatbot-challenge-on-programming-puzzles-code-golf
  2. Incolla il codice sopra nella console
  3. Inserisci alcuni comandi nella chat

Potrebbe essere giocato a golf molto di più, ma non potrebbe essere disturbato.


Un-giocato a golf:

$(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});
});

Bene, grazie per aver pubblicato una risposta qui! Ora eseguirò i test nella stanza. Ad ogni modo, penso che puoi salvare alcuni personaggi usando più variabili di una lettera ed evitando updatee latestMessage.
Programma FOX il

Grande! Hai superato tutti i test . L'unica cosa strana che ho notato è che il tuo bot ha restituito un numero di domande diverso rispetto alla pagina iniziale, ma ho visto che l'API ha restituito quel numero, quindi l'ho segnalato su Meta e contrassegnato il caso di test come corretto. Molto bene! +1
Programma FOX del

Ti ho visto abbreviare il robot. Bello! :) L'ho riprovato e hai ancora superato tutti i test.
Programma FOX

Piuttosto tardi, ma ho appena trovato un miglioramento one-char: è possibile sostituire 0==e.items.lengthcon 1>e.items.lengthquanto la lunghezza non potrà mai andare sotto lo zero.
ProgramFOX,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.