Créer un chatbot pour les salles de discussion Stack Exchange


39

Le défi

Le but de ce défi est de créer un chatbot pouvant s'exécuter dans les salles de discussion de Stack Exchange. Votre bot doit pouvoir détecter le moment où un utilisateur envoie des commandes spécifiques et y répondre. Voici la liste des commandes, et ce que votre bot devrait faire:

  • !!newest: affiche le titre (pas de lien, mais le titre) de la dernière question postée sur ce site (codegolf.SE).
  • !!metanewest: affiche le titre de la dernière question publiée sur le méta-site (meta.codegolf.SE).
  • !!questioncount: affiche le nombre de questions actuel.
  • !!metaquestioncount: affiche le nombre de questions actuel sur le méta-site.
  • !!tag tagname: affiche l'extrait de balise (la description courte) de la balise donnée en tant que premier paramètre.
  • !!metatag tagname: idem que ci-dessus, mais pour le méta-site.
  • !!featured: affiche le nombre de questions pour lesquelles une prime est actuellement disponible.
  • !!metafeatured: affiche le nombre de questions portant la balise [en vedette] sur Meta.

Règles

  1. Vous devriez écrire un programme complet, pas un extrait ou une fonction.
  2. Si cela est nécessaire, vous pouvez demander un nom d'utilisateur et un mot de passe (invite à saisir, STDIN, arguments de ligne de commande). Cela sera nécessaire si vous utilisez, par exemple, Python ou Ruby, mais pas si vous utilisez JavaScript et exécutez le script sur la page de la salle de conversation.
  3. Vous êtes autorisé à utiliser des bibliothèques externes pour effectuer des tâches telles que WebSockets. Ces bibliothèques ne doivent pas compter pour votre nombre de personnages.
  4. Vous pouvez utiliser un wrapper de discussion externe (mais vous n’avez pas à le faire, la rédaction de votre propre est encouragée), et cela doit compter pour le nombre de caractères. Vous n'êtes pas non plus autorisé à modifier le code du wrapper. Si vous l'utilisez, vous l'utilisez sans modifications et tous les caractères doivent être comptés (c'est une pénalité pour ne pas écrire votre propre wrapper).

    Seul le code du wrapper lui-même doit compter. S'il existe d'autres fichiers tels que des exemples, ceux-ci ne doivent pas compter.

  5. Aucune utilisation de raccourcisseurs d'URL ou d'autres moyens permettant de raccourcir les URL: le défi consiste à jouer au golf avec un chat, et non à jouer au golf avec une URL.
  6. Pas de demandes Web, sauf celles nécessaires pour discuter et obtenir les informations nécessaires pour répondre aux commandes.
  7. L'utilisation des "échappatoires" standard n'est pas autorisée.
  8. Si quelqu'un poste une commande, vous devez répondre avec un message de chat de ce format: @user response. Donc, si j'écris la commande !!featuredet qu'il y a 5 questions en vedette, votre bot devrait poster @ProgramFOX 5.
  9. Si je teste votre bot, je le lancerai à partir de mon compte chatbot et je le lancerai dans ce salon de discussion . Je vais toujours tester les robots dans cette salle, il n'est donc pas nécessaire de fournir un ID de salle en tant qu'entrée, il s'agira toujours de 14697. Cet ID ne sera pas donné en entrée, il devrait être codé en dur.
  10. Si la commande est introuvable, affichez @user The command [command] does not exist. Remplacez [command]par le nom de la commande inexistante. Si des arguments sont fournis à la commande, ne les affichez pas, mais uniquement le nom de la commande.
  11. Si une commande comporte plusieurs arguments, ignorez les arguments inutiles.
  12. Si une commande n'a pas assez d'arguments, sortie @user You have not provided enough arguments
  13. Le système évite que les messages en double ne soient publiés dans un court laps de temps. Ainsi, lors du test de votre bot, je n'exécuterai jamais deux commandes donnant le même résultat (ce qui signifie que vous n'avez pas à implémenter un système qui différencie les messages s'ils sont en double, en ajoutant un point par exemple).
  14. Le système évite que trop de messages ne soient envoyés dans un court laps de temps. Ainsi, lors des tests, je n’enverrai jamais trop de commandes dans un court laps de temps, ce qui signifie que votre bot n’a pas à s’occuper de cela (en attendant un certain temps). avant de poster, par exemple).
  15. C’est le , le programme avec le moins d’octets gagnés.

Commencer

Voici quelques informations pour commencer à écrire votre bot. Vous n'êtes pas obligé de l'utiliser, mais cela peut être une indication.

  • Pour vous connecter, connectez-vous d'abord à un fournisseur OpenID. Ce sera toujours Stack Exchange OpenID ( https://openid.stackexchange.com). Le formulaire de connexion se trouve à https://openid.stackexchange.com/account/loginl'adresse et indiquez le nom d'utilisateur et le mot de passe à cet endroit.
  • Ensuite, connectez-vous à stackexchange.com. Le formulaire de connexion est situé à https://stackexchange.com/users/login. Choisissez Stack Exchange en tant que fournisseur OpenID.
  • Après cela, connectez-vous pour discuter. Le formulaire de connexion pour cela est situé à http://stackexchange.com/users/chat-login. Choisissez Stack Exchange en tant que fournisseur OpenID.
  • Ensuite, vous devez obtenir votre fkey. Pour cela, accédez à http://chat.stackexchange.com/chats/join/favoriteet obtenez le à fkeypartir d'un champ de saisie masqué.
  • Pour publier un message, envoyez une demande à http://chat.stackexchange.com/chats/14697/messages/newet indiquez deux paramètres POST: un textparamètre contenant le texte du message et un fkeyparamètre contenant le fkey.
  • Pour voir quand un nouveau message est posté, vous pouvez utiliser WebSockets (mais vous n’avez pas à le faire, n'hésitez pas à utiliser autre chose si c'est plus court). S'il vous plaît voir cette réponse Meta Stack Exchange :

    Bavarder

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

    Le hachage peut être récupéré en postant l'identifiant de la salle et la touche fkey sur http://chat.stackexchange.com/ws-auth

    Le timethingy est la clé de temps du json retourné par /chats/<roomno>/events.

    L'ID d'événement lorsqu'un message est publié est 1.

  • Il est utile de regarder les wrappers de discussion existants, tels que StackExchange-Chatty de Doorknob et ChatExchange de Manishearth , pour voir comment cela fonctionne exactement.

3
Au moment où j'ai vu le titre, j'ai immédiatement pensé "ah, ProgramFOX".
seequ

J'espérais que metafeaturedcela signifierait des questions sur les primes sur méta, mais ... merci :-)
John Dvorak

@JanDvorak Les métas par site ne disposent pas de primes, je ne peux donc pas les utiliser. Quand j'ai écrit ce défi, j'avais oublié que Meta avait un tag [en vedette], alors merci pour votre suggestion!
ProgramFOX

Ce que j'ai fait pour voir si un nouveau message était posté, c’était de vérifier toutes les 2 secondes via JS si le dernier message n’était pas de moi (dernier élément de la classe)
Cilan

Nous en avons déjà un ici
M. Alien, le

Réponses:


14

JavaScript + jQuery, 1362 1258 octets

Golfé avec un 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})})

Vous devez exécuter le script directement dans le navigateur (en utilisant jQuery de Stack Exchange):

  1. Ouvrez http://chat.stackexchange.com/rooms/14697/chatbot-challenge-on-programming-puzzles-code-golf
  2. Collez le code ci-dessus dans la console
  3. Entrez des commandes dans le chat

On pourrait jouer au golf beaucoup plus, mais cela ne devrait pas être dérangé.


Non-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});
});

Nice, merci d'avoir posté une réponse ici! Je vais maintenant faire les tests dans la salle. Quoi qu'il en soit, je pense que vous pouvez enregistrer certains caractères en utilisant davantage de variables à une lettre et en évitant updateet latestMessage.
ProgramFOX

Génial! Vous avez passé tous les tests . La seule chose étrange que j'ai remarquée, c'est que votre bot a renvoyé un nombre de questions différent de celui de la page d'accueil, mais j'ai vu que l'API avait renvoyé ce nombre. J'ai donc signalé cela sur Meta et marqué le cas de test comme correct. Bien joué! +1
ProgramFOX

Je t'ai vu raccourcir le bot. Agréable! :) Je l'ai re-testé et vous passez toujours tous les tests.
ProgramFOX

Plutôt tard, mais je viens de trouver une amélioration d' un omble chevalier: vous pouvez remplacer 0==e.items.lengthavec 1>e.items.lengthparce que la longueur ne sera jamais en dessous de zéro.
ProgramFOX
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.