close

之前看到網路上很多人都在玩LINE 的LIFF,尤其是看到官方文章這篇,感覺就超級有趣的,想說自己也來寫一個玩看看,因為之前比較少接觸JavaScript,所以花了一點時間研究一下,下面來簡單講一下實作過程吧~

* LIFF(Line Front-end Framework)是一個可以在 LINE app 內運作的 web app 平台,並且浮現在對話視窗中。

* 相關LIFF 官方介紹及可以使用的API文件 => Link

* 除了要會一些python寫Chatbot,還要學一下HTML與JavaScrip一下

 

Target:

目標是建一個可以畫圖並傳送出來的LIFF,同時想說也順便加上可以即時翻譯的LINE BOT, 練習兩樣功能的實作。最後呈現如下圖,我畫的有點醜請見諒XD

drawing


Step:

1. 建立draw連結對象

如果要用LIFF畫圖就要先建立一個可以連結畫圖的網站,所以首先要先用簡單的HTML與JavaScript來架一個給我LIFF畫圖的連結(link),下面先放上我簡單寫的程式碼,很少在寫前端,所以有比較奇怪地方請告知一下。

我的後端是使用用Python的Flask框架,而前段就用HTML + Node.js

下面有幾點要注意一下

* 如果是使用Flask框架的話要注意資料夾的階層位置次序,因為Flask在跑的時候會依照資料夾名稱去抓要使用到的檔案,所以資料夾名稱也要正確才行,templates 與 static 都是相對應於主程式.py的位置,templates資料夾是存放副檔名為.html的檔案 ; 而 static 裡面分別有images 資料夾存放圖片檔案js 資料夾存放副檔名為.js的檔案

* 每次在push js檔案上去時候要記得在 <script src="..address...xxx.js?v=138"></script> 裡面更改v=後面的參數(亂打即可),如果沒有更改的話,Chrome還是會去抓之前沒修改過的,我試過刪除cookie還是一樣。

* 把所有檔案都Push到Heroku後,測試過網址沒問題後,就要到Line Developers,找到你要使用的機器人 Channel,點選列表的LIFF,就可以加入了喔~

* 圖片如果要存起來需要另外加入資料庫,我這邊是使用Heroku來暫存,所以畫完的圖過沒多久就會在heroku的路徑上消失了

 

資料檔案階層結構

階層

draw.js

window.onload = function() {
  var canvas  = document.getElementById('main');
  var canvastop = canvas.offsetTop
  var context = canvas.getContext("2d");
  var lastx;
  var lasty;
  var color = "#000000"
  var width_can = 1;
  context.strokeStyle = color;
  context.lineCap = 'round';
  context.lineJoin = 'round';
  context.lineWidth = width_can;
  function colort() {
		switch (this.id) {
            case "green":
                color = "green";
                break;
            case "blue":
                color = "blue";
                break;
            case "red":
                color = "red";
                break;
            case "yellow":
                color = "yellow";
                break;
            case "orange":
                color = "orange";
                break;
            case "black":
                color = "black";
                break;
            case "white":
                color = "white";
                break;
			case "gray":
                color = "gray";
                break;
			case "lightgreen":
                color = "#99FF99";
                break;
			case "lightblue":
                color = "#99FFFF";
                break;
			case "lighgray":
                color = "#DDDDDD";
                break;
        }
    }
	
  function clear() {
    context.fillStyle = "#ffffff";
    context.rect(0, 0, 350, 330);
    context.fill();
  }

  function share() {
		$.ajax({
		   type: 'POST',
		   url: '/fileupload',
		   data: {
			 'image': canvas.toDataURL('image/jpeg', 1.0)
		   },
		   success: function (res, status) {
			 liff.getProfile().then(function (profile) {
			   liff.sendMessages([
				 {
				   type: 'image',
				   originalContentUrl: 'https://yourURL......herokuapp.com/static/images/' + res + '.jpg',
				   previewImageUrl: 'https://yourURL.....herokuapp.com/static/images/' + res + '_240.jpg'
				 },
				 {
				   type: 'text',
				   text: '猜猜看這是什麼'
				 }
			   ]).then(function () {
				 liff.closeWindow();
			   }).catch(function (error) {
				 alert('Error sending message: ' + error.message);
			   });
			 }).catch(function (error) {
				 alert("Error getting profile: " + error.message);
			 });
		   },
		   error: function (res) {
			 alert('Error saving image: ' + res.status);
		   },
		   complete: function(data) {
			   
		   }
		 });
       liff.sendMessages([
             {
               type: 'image',
			   originalContentUrl: imgData,
			   previewImageUrl: imgData,
             }
           ]).then(()=> {
             liff.closeWindow();
			});*/
		
	}

  function showimage(){
	  switch (this.id) {
		  case "bear":
				url = "yor pic url"
				break;
	  }
	  var img = new Image();
	  img.onload = function(){
		 context.drawImage(img, 0, 0, 350, 330);
	  };
	  img.src = url;
  }
  function dot(x,y) {
    context.beginPath();
	context.lineWidth = width_can;
	context.strokeStyle = color;	
    context.fillStyle = "#000000";
    context.arc(x,y,1,0,Math.PI*2,true);
    context.fill();
    context.stroke();
    context.closePath();
  }

  function line(fromx,fromy, tox,toy) {
	context.strokeStyle = color;
	context.lineWidth = width_can;
    context.beginPath();
    context.moveTo(fromx, fromy);
    context.lineTo(tox, toy);
    context.stroke();
    context.closePath();
  }

  function show(){
	num = document.getElementById("num");
	num.innerHTML = "數值顯示:" + ran.value;
	width_can = ran.value;
  }

  canvas.ontouchstart = function(event){                   
    event.preventDefault();                 
    
    lastx = event.touches[0].clientX;
    lasty = event.touches[0].clientY - canvastop;

    dot(lastx,lasty);
  }

  canvas.ontouchmove = function(event){                   
    event.preventDefault();                 

    var newx = event.touches[0].clientX;
    var newy = event.touches[0].clientY - canvastop;

    line(lastx,lasty, newx,newy);
    
    lastx = newx;
    lasty = newy;
  }
......
......
......
......

2. 建立Line bot

Line bot 相對來說就是提供上一步的URL,有很多種方式可以呈現,像是透過 richmenu 或 關鍵字等等,在我這邊是可以透過輸入 gaming 或在 richmenu 點選,感覺LIFF還可以有很多種應用,等之後有空再來仔細來研究還有沒有什麼其他有趣的應用!

* 我這邊資料庫是連結自己搭建的MongoDB

 

Line Bot.py

"""
Created on Tue Sep 17 20:25:25 2019
deploy this application to heroku at proposalbot
@author: kevin
"""
#....import your module........

app = Flask(__name__)
line_bot_api = LineBotApi(os.getenv('Channel_access_token',None))
handler = WebhookHandler(os.getenv('Channel_secret', None))

@app.route("/callback", methods=['POST'])
def callback():
    print('----------in-------')
    # get X-Line-Signature header value
    signature = request.headers['X-Line-Signature']
    # get request body as text
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)
    # handle webhook body
    try:
        handler.handle(body,signature)

    except LineBotApiError as e:
        print("Catch exception from LINE Messaging API: %s\n" % e.message)
        for m in e.error.details:
            print("ERROR is %s: %s" % (m.property, m.message))
        print("\n")
    except InvalidSignatureError:
        abort(400)
    return 'OK'

# def init_richmenu(event):
#     _id = os.getenv('first_richmenu', None)
#     print(_id)
#     line_bot_api.link_rich_menu_to_user(event.source.user_id, _id)

@handler.add(MessageEvent, message=TextMessage)
def handle_msg_text(event):
    # init_richmenu(event)
    message = event.message.text
    profile = line_bot_api.get_profile(event.source.user_id)
    mongo = MongoOperator(profile, message)
    chat = mongo.checkChat() #沒有chat就return None
    mongo.profileExist()

    if message == 'getRiddle':
        items = mongo.gettGuess()
        print(len(items))
        r = random.randint(0, len(items)-1)
        print(r)
        t = items[r]
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text=t)
        )

    if message == 'set menu':
        _id = os.getenv('first_richmenu', None)
        print(_id)
        line_bot_api.link_rich_menu_to_user(event.source.user_id, _id)
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text = 'set')
        )

    elif event.message.text.lower() == 'all_richmenu':
        t= ''
        rich_menu_list = line_bot_api.get_rich_menu_list()
        for rich_menu in rich_menu_list:
            print(rich_menu.rich_menu_id)
            t += rich_menu.rich_menu_id
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text=t)
        )
    elif event.message.text.lower() == 'gaming':
        items = mongo.gettGuess()
        # items = ["多拉a夢", "熊", "魚"]
        r = random.randint(0, len(items) - 1)
        item = items[r]
        item = "多拉a夢"
        buttons_template = TemplateSendMessage(
            alt_text='play gmae with friend',
            template=ButtonsTemplate(
                title='Play gmae with friend',
                text='Have fun drawing and guessing according to following topic',
                thumbnail_image_url='https://i.imgur.com/TPELVeP.jpg',
                actions=[
                    MessageTemplateAction(
                        label='需要畫的題目',
                        text= item
                    ),
                    URITemplateAction(
                        label='開始畫',
                        uri='line://app/1622537665-your_URL'
                    )
                ]
            )
        )
        line_bot_api.reply_message(event.reply_token, buttons_template)
    else:
        token = Token()
        tk = token.calculate_token(message)
        print(tk)
        #sl是來源語言(Source language) ; tl是目標語言(Target language) 來源可以設定auto,但目標語言一定要設定一個特定語言->繁體中文為zh-TW 英文為en
        url = 'https://translate.google.com/translate_a/single?client=webapp&sl=auto&tl=en&hl=zh-TW&dt=at&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&dt=t&source=bh&ssel=0&tsel=0&kc=1&tk={}&q={}'.format(tk, quote(message))
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36'}
        req = requests.get(url=url, headers=headers)
        data = req.json()
        response = data[0][0][0]
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text = response)
        )
    
if __name__ == "__main__":
    port = int(os.environ.get('PORT', 5000))
    app.run(host='0.0.0.0', port=port)    
   

 


Demo:

畫畫部分:

翻譯部分:


Reference:

https://memo.domojyun.net/2019/04/25/%E8%81%8A%E5%A4%A9%E6%A9%9F%E5%99%A8%E4%BA%BA%E4%B9%8B-linebot-liff-%E7%B9%AA%E5%9C%96%E5%8A%9F%E8%83%BD/

https://www.w3schools.com/jquery/jquery_get_started.asp

https://www.wibibi.com/info.php?tid=388

http://www.wibibi.com/info.php?tid=117

https://medium.com/@md.tsai/%E6%95%B4%E7%90%86%E4%B8%80%E4%BA%9B%E4%BD%BF%E7%94%A8-viewport-%E9%8C%AF%E8%AA%A4%E9%80%A0%E6%88%90%E4%B8%8D%E7%9B%B8%E5%AE%B9%E7%9A%84%E6%A1%88%E4%BE%8B-d70cd165118e

https://stackoverflow.com/questions/2368784/draw-on-html5-canvas-using-a-mouse

https://medium.com/@danielkao/%E5%88%9D%E6%8E%A2-line-message-api-%E7%9A%84%E6%96%B0%E5%8A%9F%E8%83%BD-liff-51d5e7ff1a6a

https://pydoing.blogspot.com/2011/09/javascript-onclick.html

Ajax相關:

https://ithelp.ithome.com.tw/articles/10200409

 

arrow
arrow
    文章標籤
    LIFF LINE BOT
    全站熱搜
    創作者介紹
    創作者 KV 的頭像
    KV

    kevin的部落格

    KV 發表在 痞客邦 留言(1) 人氣()