# 佈署雲端服務 ---- https://drive.google.com/file/d/1aNk3KHI6EVUwxMCS_TiK9yBRPLyucx63/view?usp=sharing <iframe src="https://drive.google.com/file/d/1aNk3KHI6EVUwxMCS_TiK9yBRPLyucx63/preview " frameborder="0" width="100%" height="600" > </iframe> --- ![image](https://hackmd.io/_uploads/SJ-8CK-H1g.png) ---- [![](https://hackmd.io/_uploads/rkTxnCAuo.png)Iaas、Pass、Saas](https://dotblogs.com.tw/007_Lawrence/2017/08/21/155203) ---- :::spoiler **Function as a Service, FaaS**:arrow_forward: ![](https://hackmd.io/_uploads/SJP2jC0uj.png) ::: - 就是個函式 - 無狀態(stateless) - FaaS 隨叫隨開 - 事件驅動(event-triggered) ---- 御三家FaaS - [Amazon Lambda](https://aws.amazon.com/tw/lambda/) - [Google Cloud Functions](https://cloud.google.com/functions/) - [Azure Functions](https://azure.microsoft.com/en-us/services/functions/) ---- ### 以[Google Cloud Functions](https://cloud.google.com/functions/)為例 ---- ![image](https://hackmd.io/_uploads/Bk3BgpZDp.png) ---- ![image](https://hackmd.io/_uploads/SyyeZ6bPT.png) ---- ![image](https://hackmd.io/_uploads/SyUz-TbD6.png) --- [🤖 客製化你的AI教學助手-蘇格拉底引導教學法]( https://willismax.github.io/my-site/blog/Customize%20Your%20AI%20Teaching%20Assistant%20-%20A%20Socratic%20Approach) ![image](https://hackmd.io/_uploads/ryAfo4ZIa.png =600x) --- # [Vercel](https://vercel.com/) ![image](https://hackmd.io/_uploads/Sy6_gxVDT.png) --- # [fly.io](https://fly.io/) * LINE ---- ## 為何用 [fly.io](https://fly.io/) [Heroku](https://id.heroku.com/)宣布2022.11起開始收費 ![](https://hackmd.io/_uploads/Hy8Bi6Cuj.png) ---- - [fly.io](https://fly.io/)可部署Python服務,也可以直接自Heroku免費遷移專案 ![](https://hackmd.io/_uploads/rklk8Tofj.png) ---- ### [fly.io 收費標準](https://fly.io/docs/about/pricing/) :::spoiler 免費方案Hobbi :arrow_forward: ``` Free Allowances Resources included for free on all plans: Up to 3 shared-cpu-1x 256mb VMs 3GB persistent volume storage (total) 160GB outbound data transfer ``` ::: ![](https://hackmd.io/_uploads/SkpKXAado.png) --- ## [用HackMD API打造個人專屬LINE BOT助手](https://willismax.github.io/my-site/blog/%E7%94%A8HackMD%20API%E6%89%93%E9%80%A0%E5%80%8B%E4%BA%BA%E5%B0%88%E5%B1%ACLINE%20BOT%E5%8A%A9%E6%89%8B) --- ## 流程 - 完成Fly.io基本專案 - 完成LINE Developer基本設定 - 修改Fly.io程式碼 - 連結LINE與Fly.io專案 --- ## 1.完成Fly.io基本專案 ---- ### 在 Fly.io 建一個新的 Flask APP 專案 :::spoiler Lanch an APP with Python:arrow_forward: ![](https://hackmd.io/_uploads/rJO3H6jzj.png) ::: :::spoiler 以 Python 部署 Flask APP :arrow_forward: ![](https://hackmd.io/_uploads/B1ClGTr1s.png) ::: ---- 在終端機執行以建立專案 (要先裝[Git](https://git-scm.com/downloads)) ``` # clone基本專案 git clone https://github.com/fly-apps/python-hellofly-flask cd .\python-hellofly-flask\ # 安裝python相依套件 python -m pip install -r requirements.txt ``` ---- 安裝flyctl ``` ## mac brew install flyctl ## Linux curl -L https://fly.io/install.sh | sh ## Windows PowerShell iwr https://fly.io/install.ps1 -useb | iex ``` ---- ``` # 登入 fly.io flyctl auth login # 啟動一個 fly App 專案 flyctl launch ``` ---- :::spoiler 設定專案:arrow_forward: ![](https://hackmd.io/_uploads/rkRq2kyFo.png) ::: - 可能會要同意覆蓋專案(Y/n) - 選擇伺服器區域,選附近的(香港或東京) ``` ? Overwrite "D:\dev\NUTC-CSIE-MS\python-hellofly-flask\Procfile"? Yes ? Choose an app name (leave blank to generate one): ? Choose a region for deployment: Tokyo, Japan (nrt) ? Would you like to set up a Postgresql database now? No ? Would you like to set up an Upstash Redis database now? No We have generated a simple Procfile for you. Modify it to fit your needs and run "fly deploy" to deploy your application. ``` ---- - 修改`Procfile`的程式碼,`hellofly`為主程式 ``` # file name: Procfile web: gunicorn hellofly:app ^^^^^^^^ ``` ---- - 檢查完程式後,一鍵佈署。 ``` flyctl deploy ``` ![](https://hackmd.io/_uploads/H1NsCkkFi.png) ---- :::spoiler 查看狀態與部署結果:arrow_forward: ![](https://hackmd.io/_uploads/SJVtyxyYj.png) ::: ``` flyctl status ``` ``` flyctl open ``` ![](https://hackmd.io/_uploads/ByV3kgJYj.png) ---- (最後)設定後續本機測試及開發環境 ``` //設置環境變數`FLASK_APP` #linux export FLASK_APP=hellofly.py #windows set FLASK_APP=hellofly.py //日後啟動flask的指令 flask run ``` ``` //如果用環境變數都跑不出來,退而求其次,在`hellofly.py`最後加入 if __name__ == '__main__': app.run(debug=True) //日後啟動flask的指令 python hello.py #但[這不是flask建議的啟用方式https://www.maxlist.xyz/2020/04/30/flask-helloworld/)。 ``` ---- [設定secrets](https://fly.io/docs/reference/secrets/) ``` #新增 secrets flyctl secrets set DATABASE_URL= .... #取消 secrets flyctl secrets unset DATABASE_URL= .... #列出 secrets list flyctl secrets list ``` --- ## 2.完成LINE Developer基本設定 (建立程式可控的 LINE@ 服務) ---- - 目標為建立 LINE Developer Channel - 並取得 `Channel ID`、 `Channel Secret` 、 `Channel Access Token` 。 ---- ## [LINE Developer](https://developers.line.biz/zh-hant/) - 右上方登入(LINE帳號即可) [![](https://hackmd.io/_uploads/HkNojSILo.png)](https://developers.line.biz/zh-hant/) ---- :::spoiler 1.創Provider:arrow_forward: ![](https://hackmd.io/_uploads/Sy9V6SLUs.png) ::: :::spoiler 2.創Channel:arrow_forward: ![](https://hackmd.io/_uploads/Hko56BI8j.png) ::: :::spoiler 3.選MessageAPI:arrow_forward: ![](https://hackmd.io/_uploads/HJO06BLIs.png) ::: ---- :::spoiler 4.建立基本資訊:arrow_forward: |![](https://hackmd.io/_uploads/HJRPJLLUs.png)|![](https://hackmd.io/_uploads/HyL1yL8Lj.png) |:-:|:-:| ::: :::spoiler 4.建立基本資訊:arrow_forward: |![](https://hackmd.io/_uploads/HJdxyLLIo.png)|![](https://hackmd.io/_uploads/ByIbkILIi.png) |:-:|:-:| ::: ---- - 同意創立後,取得**Channel ID**、**Channel Secret** (在Basic Setting ) |![](https://hackmd.io/_uploads/Sy9zxUIIs.png)|![](https://hackmd.io/_uploads/SkNggI88s.png) |:-:|:-: ---- - 取得**Channel access token** (在 Messaging API 分頁,按issue產生) |![](https://hackmd.io/_uploads/rJ6axU8Ii.png)|![](https://hackmd.io/_uploads/rk-z-LLIo.png) |:-:|:-: ---- - 現在有了`Channel ID`、 `Channel Secret` 、 `Channel Access Token` 。 - 等伺服器程式處理好,用webhook連結就完成了 ---- - 通常會把系統預設回應關掉 - 通常會加入圖文選單 --- ## 3.修改Fly.io程式碼 ---- ## <i class="fa fa-github" aria-hidden="true"></i> [Line-bot-fly-flask](https://github.com/willismax/MediaSystem-Python-Course/tree/main/line-bot-fly-flask) ---- 在hellofly修改專案檔案 :::spoiler 修改部分檔案 :arrow_forward: ![](https://hackmd.io/_uploads/BJtOMJGFi.png) ::: ---- :::spoiler my_moduls/: 自製模組 :arrow_forward: ![](https://hackmd.io/_uploads/ByvnHyzFs.png) ::: ---- :::spoiler app.py: 主程式 :arrow_forward: ```python= from flask import Flask, request, abort from linebot import LineBotApi, WebhookHandler from linebot.exceptions import InvalidSignatureError from linebot.models import ( MessageEvent, TextMessage, ImageMessage, TextSendMessage ) import my_moduls.hackmd_bot as hb import my_moduls.my_functions as mf from my_moduls.openai_bot import OpenAIBot from config import ( CHANNEL_ACCESS_TOKEN, CHANNEL_SECRET, LINE_USER_ID, TEMP_NOTE_ID ) import os app = Flask(__name__) line_bot_api = LineBotApi(CHANNEL_ACCESS_TOKEN) handler = WebhookHandler(CHANNEL_SECRET) chatgpt = OpenAIBot() # Messages on start and restart line_bot_api.push_message( LINE_USER_ID, TextSendMessage(text='HackMD Bot Starting') ) # Listen for all Post Requests from /callback @app.route("/callback", methods=['POST']) def callback(): # 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 InvalidSignatureError: abort(400) return 'OK' @handler.add(MessageEvent, message=(TextMessage, ImageMessage)) def handle_message(event): """LINE MessageAPI message processing""" if event.source.user_id =='Udeadbeefdeadbeefdeadbeefdeadbeef': return 'OK' if event.message.type=='image': image = line_bot_api.get_message_content(event.message.id) path = hb.get_user_image(image) link = hb.upload_img_link(path) content = hb.add_temp_note(content = f"![]({link})") message = TextSendMessage(text=content) line_bot_api.reply_message(event.reply_token, message) if event.message.type=='text': word = str(event.message.text) if word[:3] == "@fletting": content = hb.creat_fletting_note(word[3:]) message = TextSendMessage(text=content) line_bot_api.reply_message(event.reply_token, message) elif word[:5] == "@todo": content = hb.update_todo_note(word[5:]) message = TextSendMessage(text=content) line_bot_api.reply_message(event.reply_token, message) elif word[:3] == "@ai": content = event.message.text chatgpt.add_msg(f"HUMAN:{content}?\n") reply_msg = chatgpt.get_response() message = TextSendMessage(text=reply_msg) line_bot_api.reply_message(event.reply_token, message) elif event.message.text[:3] == "@翻英": content = mf.translate_text(event.message.text[3:], "en") message = TextSendMessage(text=content) line_bot_api.reply_message(event.reply_token, message) elif event.message.text[:3] == "@翻日": content = mf.translate_text(event.message.text[3:] , "ja") message = TextSendMessage(text=content) line_bot_api.reply_message(event.reply_token, message) elif event.message.text[:3] == "@翻中": content = mf.translate_text(event.message.text[3:] , "zh-tw") message = TextSendMessage(text=content) line_bot_api.reply_message(event.reply_token, message) elif event.message.text[:3] == "@違法": content = mf.query_illegal_announcement(event.message.text[3:]) message = TextSendMessage(text=content) line_bot_api.reply_message(event.reply_token, message) elif event.message.text[:3] == "@職務": content = mf.search_jobbooks(event.message.text[3:]) message = TextSendMessage(text=content) line_bot_api.reply_message(event.reply_token, message) elif event.message.text[:3] == "@選單": content = f"@翻英、@翻日、@翻中、@違法、@職務、@ai,或存https://hackmd.io/{TEMP_NOTE_ID}" message = TextSendMessage(text=content) line_bot_api.reply_message(event.reply_token, message) else: content = hb.add_temp_note(word) message = TextSendMessage(text=content) line_bot_api.reply_message(event.reply_token, message) # if __name__ == "__main__": # port = int(os.environ.get('PORT', 5000)) # app.run(host='0.0.0.0', port=port) ::: ---- :::spoiler Procfile: 設定wsgi用 :arrow_forward: ``` # Modify this Procfile to fit your needs # web: gunicornapp-hellofly:app # web: gunicorn app_for_tools:app # web: gunicorn app_for_openaibot:app # web: gunicorn app_for_hackmdbot:app web: gunicorn app:app ``` ::: ---- :::spoiler config.py: 各種Token :arrow_forward: ``` CHANNEL_ACCESS_TOKEN = "" CHANNEL_SECRET = "" LINE_USER_ID = '' OPENAI_API_KEY = '' HACKMD_USER_NAME = '' IMGUR_CLIENT_ID = '' HACKMD_API_TOKEN = '' TODO_NOTE_ID = '' # paste your fixed TODO note id TEMP_NOTE_ID = '' # paste your fixed TEMP note id ``` ::: ---- :::spoiler config.py: 各種Token :arrow_forward: ``` click Flask gunicorn itsdangerous Jinja2 MarkupSafe Werkzeug googletrans==3.1.0a0 line-bot-sdk requests pandas lxml bs4 PyHackMD pyimgur openai ``` ---- ``` flyctl deploy ``` ``` flyctl logs ``` --- ## 4.連結LINE與Fly.io專案 ---- ![](https://hackmd.io/_uploads/Bkj1K1Mti.png) ---- ![](https://hackmd.io/_uploads/Bk4NK1zYo.png) --- ## [流程整理](https://hackmd.io/@wiimax/hackmd_line_chat_bot)
{"metaMigratedAt":"2023-06-17T07:40:52.693Z","metaMigratedFrom":"YAML","title":"佈署雲端服務","breaks":false,"GA":"G-CH7FZ71WRC","slideOptions":"{\"author\":\"Willis Chen\",\"slideOptions\":null,\"transition\":\"slide\",\"slideNumber\":true,\"theme\":\"sky\",\"type\":\"slide\",\"GA\":\"G-CH7FZ71WRC\"}","description":"https://drive.google.com/file/d/1aNk3KHI6EVUwxMCS_TiK9yBRPLyucx63/view?usp=sharing","contributors":"[{\"id\":\"16a0caa2-a39b-4d8d-b3f1-bac2f0b61a6d\",\"add\":20184,\"del\":8377}]"}
    2919 views