Simple chatbot

151 views
Skip to first unread message

Maurice Waka

unread,
Nov 10, 2017, 4:30:40 AM11/10/17
to web2py-users
Hi everyone.
For several months, though not a python expert, nor a web2py guru either, I have been working on a simple bot. I borrowed from this site: https://codepen.io/pavel_komiagin/pen/gaGJJK

My code is this:
{{extend "layout.html"}}

<html lang="en">
{{for q in question:}}
{{q=XML(unicode(q.quest.replace('\n','<br>')))}}
{{pass}}
{{for a in answer:}}
{{a=XML(unicode(a.message.replace('\n','<br>')))}}
{{pass}}

</style>
    <script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
</head>
<body>
    <div class="chat_window">
          <ul class="messages">
              {{for reply in replies:}}
              <li class="message left appeared">
                  <div>
                      {{=prettydate(reply.modified_on)}}
                  </div>
                  <div class="text_wrapper">
                      <div class="text">{{=XML(unicode(reply.quest.replace('\n','<br>')))}}</div>
                  </div>
              </li>
              <li class="message right appeared">
                  <div class="text_wrapper">
                      <div class="text">{{=XML(unicode(reply.message.replace('\n','<br>')))}}</div>
                  </div>
              </li>
              {{pass}}
          </ul>
        <div class="bottom_wrapper clearfix">
            <div class="message_input_wrapper">
                {{=form.custom.begin}}
                <textarea name="message" id="message_input" placeholder="Type your message here..."></textarea>
                <button>send</button>
                {{=form.custom.end}}
            </div>
        </div>
    </div>
    <div class="message_template">
        <li class="message">
            <div class="message-data-time" >{{=time.ctime()}}</div>
            <div class="text_wrapper">
                <div class="text"></div>
            </div>
        </li>
    </div>

<script type="text/javascript">
    (function () {
        var Message;
        Message = function (arg) {
            this.text = arg.text, this.message_side = arg.message_side;
            this.draw = function (_this) {
                return function () {
                    var $message;
                    $message = $($('.message_template').clone().html());
                    $message.addClass(_this.message_side).find('.text').html(_this.text);
                    $('.messages').append($message);
                    return setTimeout(function () {
                        return $message.addClass('appeared');
                        }, 0);
                    };
                }(this);
            return this;
            };
        $(function () {
            var getMessageText, message_side, sendMessage;
            message_side = 'right';
            getMessageText = function () {
                var $message_input;
                $message_input = $('.message_input');
                return $message_input.val();
                };
            sendMessage = function (text) {
                var $messages, message;
                if (text.trim() === '') {
                    return;
                    }
                $('.message_input').val('');
                $messages = $('.messages');
                message_side = message_side === 'left' ? 'right' : 'left';
                message = new Message({
                    text: text,
                    message_side: message_side
                    });
                message.draw();
                return $messages.animate({ scrollTop: $messages.prop('scrollHeight') }, 5);
                };
            $('.send_message').click(function (e) {
                //e.preventDefault();//new
                return sendMessage(getMessageText());
                });
            $('.message_input').keyup(function (e) {
                if (e.which === 13) {
                    e.preventDefault();//new
                    return sendMessage(getMessageText());
                    }
                });

            //sendMessage('Wait a moment please...!')
            setTimeout(function () {
                return sendMessage('{{=q}}');
                }, 100);
            return setTimeout(function () {
                return sendMessage('{{=a}}');
                }, 2100);
            });
        }.call(this));

</script>
</body>
</html>

  • So far the system works well with a user input such as 'Hello',and the string goes through a code to randomly select an answer . 
  • The answer and the question('Hello') are posted in the answer db. 
  • The controller returns the question and answer (both different columns) rows. 
  • Many users login and are able to retrieve the answers(This has been sorted out as each user is able to get his/her answer from the rows, without seeing other rows by other users...see below


Problem:
  • On the view side, the cursor is always at the top of the page and when the user posts the message
  • the page refreshes first then the cursor moves to the bottom of the page then you see the new message appearing
  • some times when the user posts the message/question, it appears at the bottom of the page as well as the last posted message in the db, hence using the   " db.answers.ALL)[-5:-1] " code foe the last 5 rows minus the last row.
  • I cant get a clear prettydate on the new message. See image below
I need help to sort out these problems, i have tried using websockets(w2pchat) but it requires that two or more users be logged in to post and see the messages as they come in. What I need is a system, as it is where the 'other user' is the bot.
I also don't want page refreshed on posting the question, that it works like other bots where the messages appear from the bottom as they come in. Ifigured out that maybe as the page refreshes, that's when the cursor moves first up then to the bottom of the page, then the message appears.
I dont mind a new code or referral.

N/B
The cursor here is the scroll bar.Sorry fort he mixup

Regards

Dave S

unread,
Nov 11, 2017, 1:32:15 AM11/11/17
to web...@googlegroups.com


On Friday, November 10, 2017 at 1:30:40 AM UTC-8, Maurice Waka wrote:
Hi everyone.
For several months, though not a python expert, nor a web2py guru either, I have been working on a simple bot. I borrowed from this site: https://codepen.io/pavel_komiagin/pen/gaGJJK
[...]
I also don't want page refreshed on posting the question, that it works like other bots where the messages appear from the bottom as they come in. Ifigured out that maybe as the page refreshes, that's when the cursor moves first up then to the bottom of the page, then the message appears.
I dont mind a new code or referral.

That "append to the current page" stuff is ajax.  Web2py has a very handy wrapper for ajax, the LOAD() helper.
<URL:http://web2py.com/books/default/chapter/29/12/components-and-plugins#LOAD>
The target argument specifies where on the page to put the results ... you need a DIV that matches.

My example, which goes in the view file:

{{=LOAD(c='myhosts', f='myhosts2.load', target='my_hosts', content="something's happening", ajax=True)}}


To continually append more messages, instead of replacing old with new, you would need to have multiple DIVs, and point to a different DIV for each message.

The above code will run automatically on initial page load, which you may or may not want, depending on whether you want messages from a previous visit to appear.

I have done some stuff where I want a user to click a button to get more information, and so I fabricate an html string in the controller, put the string into the dict I return, and the view displays the string in the appropriate part of the page.

The string includes something like this:

    dis_str = CAT("other stuff to display", TT("                                "),
                 A
("mystuff list", _href=URL("mystuff.html", vars=dict(ipaddr=ipaddr, hnam
e
=hname, tdisk=index)),
                    _style
="visibility:visible", _id="stuffh"),
                TT
("\n        "),
                TAG
.BUTTON('mystuff list', _type="button", _name="val2controller", _value=val2controller,
                             _onclick
='$("#mystuff_div").html("updating ..");ajax("mystuff.load", ["val2controller"], "mystuff_div")',
                             _style
="display:none", _id="mystuffa"))

I think you can manipulate the DIV name either server side or client side, but I haven't tested any code for that purpose.

Server side: keep the name in the session object, update it on each load, and in the view/controller/response.load file use the DIV helper after you display your messages.  This will end up nesting the DIVs, but I don't think that's a problem.  Caveat coder.

Client side:  use javascript to tap into the onclick path, and insert a new DIV into the DOM, then use that DIV's name in the ajax call.  You may have to go direct to ajax in this scheme, rather than using the LOAD helper.  This will require a little more study, but look at the other material in the book's component chapter, and it may help you out.

Note that using ajax requires that your users allow javascript from your site, and there are plenty of people reluctant to do that, but if they are going to trust your site they might as well trust your site.  Using something like noscript gives them some confidence that they protected against cross-site scripting attacks, but they can whitelist your site to view your pages.  (noscript is for firefox; I don't know the equivalent in other browsers, but chrome has some of the features built in but not as easily tuned.)

Good luck!  I hope this helps, and that I haven't fed you too much bogus information.

/dps

Maurice Waka

unread,
Nov 11, 2017, 5:58:15 AM11/11/17
to web...@googlegroups.com
Thanks for the reply and details. It will take me several weeks juts to get something to work out. As I had said, am not an expert in this as I do part time programming; I have to study it first then practice till I get something to work out.
Is it OK if you give me a working example?...😜
Kind regards

On Sat, Nov 11, 2017 at 9:32 AM, Dave S <snide...@gmail.com> wrote:


On Friday, November 10, 2017 at 1:30:40 AM UTC-8, Maurice Waka wrote:
Hi everyone.
For several months, though not a python expert, nor a web2py guru either, I have been working on a simple bot. I borrowed from this site: https://codepen.io/pavel_komiagin/pen/gaGJJK
[...]
I also don't want page refreshed on posting the question, that it works like other bots where the messages appear from the bottom as they come in. Ifigured out that maybe as the page refreshes, that's when the cursor moves first up then to the bottom of the page, then the message appears.
I dont mind a new code or referral.

That "append to the current page" stuff is ajax.  Web2py has a very handy wrapper for ajax, the LOAD() helper.
<URL:http://web2py.com/books/default/chapter/29/12/components-and-plugins#LOAD>
The target argument specifies where on the page to put the results ... you need a DIV that matches.

My example, which goes in the view file:

{{=LOAD(c='myhosts', f='myhosts2.load', target='my_hosts', content="something's happening", ajax=True)}}


To continually append more messages, instead of replacing old with new, you would need to have multiple DIVs, and point to a different DIV for each message.

The above code will run automatically on initial page load, which you may or may not want, depending on whether you want messages from a previous visit to appear.

I have done some stuff where I want a user to click a button to get more information, and so I fabricate an html string in the controller, put the string into the dict I return, and the view displays the string in the appropriate part of the page.

The string includes something like this:

    dis_str = CAT(dis_str, TT("                                "),

                 A
("mystuff list", _href=URL("mystuff.html", vars=dict(ipaddr=ipaddr, hnam
e
=hname, tdisk=index)),
                    _style
="visibility:visible", _id="stuffh"),
                TT
("\n        "),
                TAG
.BUTTON('mystuff list', _type="button", _name="val2controller", _value=val2controller,
                             _onclick
='$("#mystuff_div").html("updating ..");ajax("mystuff.load", ["val2controller"], "mystuff_div")',
                             _style
="display:none", _id="mystuffa"))

I think you can manipulate the DIV name either server side or client side, but I haven't tested any code for that purpose.

Server side: keep the name in the session object, update it on each load, and in the view/controller/response.load file use the DIV helper after you display your messages.  This will end up nesting the DIVs, but I don't think that's a problem.  Caveat coder.

Client side:  use javascript to tap into the onclick path, and insert a new DIV into the DOM, then use that DIV's name in the ajax call.  You may have to go direct to ajax in this scheme, rather than using the LOAD helper.  This will require a little more study, but look at the other material in the book's component chapter, and it may help you out.

Note that using ajax requires that your users allow javascript from your site, and there are plenty of people reluctant to do that, but if they are going to trust your site they might as well trust your site.  Using something like noscript gives them some confidence that they protected against cross-site scripting attacks, but they can whitelist your site to view your pages.  (noscript is for firefox; I don't know the equivalent in other browsers, but chrome has some of the features built in but not as easily tuned.)

Good luck!  I hope this helps, and that I haven't fed you too much bogus information.

/dps

--
Resources:
- http://web2py.com
- http://web2py.com/book (Documentation)
- http://github.com/web2py/web2py (Source code)
- https://code.google.com/p/web2py/issues/list (Report Issues)
---
You received this message because you are subscribed to a topic in the Google Groups "web2py-users" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/web2py/eH5y3Yvz56Q/unsubscribe.
To unsubscribe from this group and all its topics, send an email to web2py+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Maurice Waka

unread,
Nov 11, 2017, 10:13:31 PM11/11/17
to web...@googlegroups.com
Why I said that:
  1. Loading takes too long  to load
  2. I get an error: invalid controller..see below


Dave S

unread,
Nov 12, 2017, 2:33:54 PM11/12/17
to web2py-users


On Saturday, November 11, 2017 at 7:13:31 PM UTC-8, Maurice Waka wrote:
Why I said that:
  1. Loading takes too long  to load
  2. I get an error: invalid controller..see below




Loading takes too long?  the LOAD helper should be faster than a page refresh, give or take a cache hit.

Do you have the file my-chatbot-app/controllers/messages.py, and does it have the function answers() ?

/dps

 
To unsubscribe from this group and all its topics, send an email to web2py+un...@googlegroups.com.

Maurice Waka

unread,
Nov 13, 2017, 12:13:26 AM11/13/17
to web...@googlegroups.com
I don't have it.
Let me work it out

To unsubscribe from this group and all its topics, send an email to web2py+unsubscribe@googlegroups.com.

Maurice Waka

unread,
Nov 13, 2017, 1:18:15 AM11/13/17
to web...@googlegroups.com
Sorry I cant make any head, nor tail of this.I need you help

Maurice Waka

unread,
Nov 13, 2017, 4:06:15 PM11/13/17
to web...@googlegroups.com
in my controller:
def view_searches:
    if db(db.post).isempty():
        db.post.insert(message="Hi, it's" +' ' +auth.user.first_name+' '+ 'loging in...')
    form = SQLFORM(Post, formstyle='table3cols',)
    if form.process().accepted:
        pass
    long code...
    replies = db(db.answers.author == auth.user.id).select(db.answers.ALL)[-5:5]
    return dict(form = SQLFORM(Post, formstyle='table3cols',).process(),
                replies = db(db.answers.author == auth.user.id).select(db.answers.ALL)[-5:5])


html page:

{{extend "layout.html"}}

{{=LOAD('replies','view_searches.load',ajax=True)}}


error message on loading view_searches.html:

invalid controller (replies/view_searches)


This is how far I've come

Maurice Waka

unread,
Nov 13, 2017, 5:21:40 PM11/13/17
to web...@googlegroups.com
I got the error resolved:
{{=LOAD('default','view_searches.load',ajax=True)}} 
instead of :
{{=LOAD('replies','view_searches.load',ajax=True)}}

Dave S

unread,
Nov 14, 2017, 2:31:31 AM11/14/17
to web2py-users


On Monday, November 13, 2017 at 2:21:40 PM UTC-8, Maurice Waka wrote:
I got the error resolved:
{{=LOAD('default','view_searches.load',ajax=True)}} 
instead of :
{{=LOAD('replies','view_searches.load',ajax=True)}}


Yes, in web2py it is very important to have the controller in the LOAD() match the filename in myapp/controllers.
(and in other URL references, too)

/dps
 
Reply all
Reply to author
Forward
0 new messages