สร้าง chatbot สำหรับห้องสนทนา Stack Exchange


39

ความท้าทาย

เป้าหมายของความท้าทายนี้คือการสร้าง chatbot ที่สามารถทำงานได้ใน chatrooms ของ Stack Exchange บอตของคุณต้องสามารถตรวจจับได้เมื่อผู้ใช้โพสต์คำสั่งเฉพาะและตอบกลับ นี่คือรายการคำสั่งและสิ่งที่บอทของคุณควรทำ:

  • !!newest: แสดงชื่อ (ไม่มีลิงก์ แต่เป็นชื่อ) ของคำถามล่าสุดที่โพสต์บนเว็บไซต์นี้ (codegolf.SE)
  • !!metanewest: แสดงชื่อคำถามล่าสุดที่โพสต์บนเว็บไซต์ meta (meta.codegolf.SE)
  • !!questioncount: เอาท์พุทนับคำถามปัจจุบัน
  • !!metaquestioncount: แสดงผลจำนวนคำถามปัจจุบันบนไซต์เมตา
  • !!tag tagname: เอาท์แท็กข้อความที่ตัดตอนมา (คำอธิบายสั้น ๆ ) ของแท็กที่ได้รับเป็นพารามิเตอร์แรก
  • !!metatag tagname: เหมือนด้านบน แต่สำหรับไซต์เมตา
  • !!featured: เอาท์พุทนับคำถามที่ปัจจุบันมีความโปรดปราน
  • !!metafeatured: แสดงจำนวนคำถามที่มีแท็ก[เด่น]บน Meta

กฎระเบียบ

  1. คุณควรเขียนโปรแกรมที่สมบูรณ์ไม่ใช่ตัวอย่างหรือฟังก์ชั่น
  2. ในกรณีที่จำเป็นคุณสามารถขอชื่อผู้ใช้และรหัสผ่านเป็นอินพุต (พร้อมท์ใส่, STDIN, อาร์กิวเมนต์บรรทัดคำสั่ง) สิ่งนี้จะจำเป็นถ้าคุณใช้เช่น Python หรือ Ruby แต่ไม่จำเป็นถ้าคุณใช้ JavaScript และรันสคริปต์บนหน้าห้องสนทนาเอง
  3. คุณได้รับอนุญาตให้ใช้ไลบรารีภายนอกเพื่อทำสิ่งต่าง ๆ เช่น WebSockets ไลบรารีเหล่านี้ไม่จำเป็นต้องนับสำหรับการนับตัวละครของคุณ
  4. คุณสามารถใช้ wrapper การแชทภายนอก (แต่คุณไม่จำเป็นต้องเขียนตัวคุณเอง) และจากนั้นต้องนับจำนวนตัวอักษร คุณไม่ได้รับอนุญาตให้เปลี่ยนรหัสของ wrapper ถ้าคุณใช้มันคุณจะใช้มันโดยไม่มีการดัดแปลงและต้องนับตัวอักษรทั้งหมด (นั่นเป็นโทษสำหรับการไม่เขียนเสื้อคลุมของคุณเอง)

    มีเพียงการนับรหัสของ wrapper เท่านั้น หากมีไฟล์อื่น ๆ เช่นตัวอย่างสิ่งเหล่านี้ไม่จำเป็นต้องนับ

  5. ไม่มีการใช้ตัวย่อ URL หรือวิธีอื่น ๆ ที่ทำให้ URL สั้นลง: ความท้าทายคือการเล่นแชทบ็อตไม่ใช่เล่นกอล์ฟ URL
  6. ไม่มีคำขอทางเว็บยกเว้นที่จำเป็นในการแชทและรับข้อมูลที่จำเป็นในการตอบสนองต่อคำสั่ง
  7. ไม่อนุญาตให้ใช้"ช่องโหว่" มาตรฐาน
  8. @user responseถ้าคนโพสต์คำสั่งคุณจำเป็นต้องตอบสนองด้วยข้อความแชทของรูปแบบนี้: ดังนั้นถ้าผมเขียนคำสั่ง!!featuredและมี 5 คำถามที่โดดเด่น, @ProgramFOX 5บอทของคุณควรโพสต์
  9. หากฉันทดสอบบอทของคุณฉันจะเรียกใช้จากบัญชี chatbotของฉันและฉันจะเรียกใช้ในห้องสนทนานี้ ฉันจะทดสอบบ็อตในห้องนั้นเสมอดังนั้นจึงไม่จำเป็นที่จะต้องระบุ ID ห้องเป็นอินพุตมันจะเป็น 14,697 เสมอ ID นี้จะไม่ได้รับเป็นข้อมูลเข้าควรเป็นรหัสที่ยาก
  10. @user The command [command] does not existถ้าคำสั่งไม่พบการส่งออก แทนที่[command]ด้วยชื่อของคำสั่งที่ไม่มีอยู่ หากมีการระบุอาร์กิวเมนต์ให้กับคำสั่งห้ามส่งออกอาร์กิวเมนต์เพียงชื่อคำสั่งเท่านั้น
  11. หากคำสั่งมีหลายอาร์กิวเมนต์ให้ข้ามข้อโต้แย้งที่ไม่จำเป็น
  12. หากคำสั่งมีอาร์กิวเมนต์ไม่เพียงพอเอาต์พุต @user You have not provided enough arguments
  13. ระบบป้องกันไม่ให้มีการโพสต์ข้อความที่ซ้ำกันภายในช่วงเวลาสั้น ๆ ดังนั้นเมื่อทดสอบบอทของคุณฉันจะไม่รันคำสั่งสองคำสั่งที่ให้เอาต์พุตเดียวกันอย่างต่อเนื่อง (ซึ่งหมายความว่าคุณไม่จำเป็นต้องใช้ระบบที่ทำให้ข้อความแตกต่างหากพวกเขาซ้ำกันโดยเพิ่มจุดเป็นตัวอย่าง)
  14. ระบบป้องกันไม่ให้มีการโพสต์ข้อความมากเกินไปในช่วงเวลาสั้น ๆ ดังนั้นเมื่อทำการทดสอบฉันจะไม่ส่งคำสั่งมากเกินไปในช่วงเวลาสั้น ๆ ซึ่งหมายความว่าบอทของคุณไม่ต้องคอยดูแล (โดยรอสักครู่ ก่อนโพสต์ตัวอย่าง)
  15. นี่คือโปรแกรมที่มีจำนวนไบต์น้อยที่สุดจะเป็นผู้ชนะ

เริ่มต้นใช้งาน

นี่คือข้อมูลบางส่วนในการเริ่มต้นเขียน bot ของคุณ คุณไม่จำเป็นต้องใช้สิ่งนี้ แต่สามารถเป็นแนวทางได้

  • เพื่อเข้าสู่ระบบก่อนเข้าสู่ผู้ให้บริการ OpenID นี่จะเป็น Stack Exchange OpenID ( https://openid.stackexchange.com) เสมอ แบบฟอร์มการเข้าสู่ระบบอยู่ที่https://openid.stackexchange.com/account/loginและให้ชื่อผู้ใช้และรหัสผ่านที่นั่น
  • stackexchange.comจากนั้นเข้าสู่ระบบ https://stackexchange.com/users/loginแบบฟอร์มการเข้าสู่ระบบตั้งอยู่ที่ เลือก Stack Exchange เป็นผู้ให้บริการ OpenID
  • หลังจากนั้นให้เข้าสู่ระบบแชท http://stackexchange.com/users/chat-loginแบบฟอร์มการเข้าสู่ระบบที่ตั้งอยู่ที่ เลือก Stack Exchange เป็นผู้ให้บริการ OpenID
  • fkeyแล้วคุณจะต้องได้รับของคุณ เพื่อที่จะไปhttp://chat.stackexchange.com/chats/join/favoriteและรับfkeyจากช่องใส่ที่ซ่อนอยู่
  • โพสต์ข้อความที่ส่งคำขอไปhttp://chat.stackexchange.com/chats/14697/messages/newและให้สองพารามิเตอร์ POST กtextพารามิเตอร์ที่มีข้อความและพารามิเตอร์ที่มีfkeyfkey
  • เมื่อต้องการดูว่ามีการโพสต์ข้อความใหม่เมื่อใดคุณสามารถใช้ WebSockets (แต่ไม่จำเป็นต้องลังเลที่จะใช้อย่างอื่นหากข้อความสั้นลง) โปรดดูคำตอบ Meta Stack Exchange นี้ :

    การพูดคุย

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

    สามารถแฮชสามารถดึงข้อมูลได้โดยโพสต์ ID ห้องและ fkey ไปที่ http://chat.stackexchange.com/ws-auth

    timethingy เป็นกุญแจสำคัญเวลาของการ JSON /chats/<roomno>/eventsกลับโดย

    เหตุการณ์ ID 1เมื่อข้อความถูกโพสต์

  • มันจะมีประโยชน์ในการดู chat-wrappers ที่มีอยู่แล้วเช่นStackExchange-Chattyของ Doorknob และ ChatExchange ของManishearthเพื่อดูว่ามันทำงานอย่างไร

3
ช่วงเวลาที่ฉันเห็นชื่อฉันคิดทันที "ah, ProgramFOX"
Seequ

ฉันหวังว่าmetafeaturedจะหมายถึงคำถามเกี่ยวกับเมตาดาต้า แต่ ... ขอบคุณ :-)
John Dvorak

@JanDvorak ข้อมูลเมตาสำหรับแต่ละไซต์ไม่มีรางวัลดังนั้นฉันจึงใช้ไม่ได้ เมื่อฉันเขียนความท้าทายนี้ฉันลืม Meta ที่มีแท็ก [เด่น] ดังนั้นขอบคุณสำหรับคำแนะนำของคุณ!
ProgramFOX

สิ่งที่ฉันได้เพื่อดูว่ามีข้อความใหม่ถูกโพสต์ก็ตรวจสอบทุก 2 วินาทีผ่าน JS ถ้าข้อความสุดท้ายไม่ได้โดยฉัน (รายการสุดท้ายในชั้นเรียน)
Cilan

คำตอบ:


14

JavaScript + jQuery, 1362 1258 ไบต์

เล่นกอล์ฟโดยใช้ 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})})

คุณต้องเรียกใช้สคริปต์โดยตรงในเบราว์เซอร์ (ใช้ jQuery ของ Stack Exchange):

  1. เปิดhttp://chat.stackexchange.com/rooms/14697/chatbot-challenge-on-programming-puzzles-code-golf
  2. วางรหัสด้านบนในคอนโซล
  3. ป้อนคำสั่งบางอย่างในการแชท

มันสามารถเล่นกอล์ฟได้มากขึ้น แต่ก็ไม่สามารถรบกวนได้


ยกเลิกแข็งแรงเล่นกอล์ฟ:

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

เยี่ยมมากขอบคุณที่โพสต์คำตอบที่นี่! ตอนนี้ฉันจะทำการทดสอบในห้อง อย่างไรก็ตามผมคิดว่าคุณสามารถบันทึกตัวอักษรบางอย่างโดยใช้ตัวแปรหนึ่งตัวอักษรและหลีกเลี่ยงและupdate latestMessage
ProgramFOX

ที่ดี! คุณผ่านการทดสอบทั้งหมด สิ่งเดียวที่ฉันสังเกตเห็นได้คือบอทของคุณส่งคืนจำนวนคำถามที่แตกต่างจากในหน้าแรก แต่ฉันเห็นว่า API ส่งคืนหมายเลขนั้นดังนั้นฉันจึงรายงานเรื่องนี้บน Metaและทำเครื่องหมายกรณีทดสอบให้ถูกต้อง ทำได้ดี! +1
ProgramFOX

ฉันเห็นคุณทำให้บอทสั้นลง ดี! :) ฉันทดสอบอีกครั้งและคุณยังคงผ่านการทดสอบทั้งหมด
ProgramFOX

ค่อนข้างช้า แต่ฉันเพิ่งพบการปรับปรุงแบบตัวเดียว: คุณสามารถแทนที่0==e.items.lengthด้วย1>e.items.lengthเพราะความยาวจะไม่ต่ำกว่าศูนย์
ProgramFOX
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.