changed 6 months ago
Linked with GitHub

佈署雲端服務


https://drive.google.com/file/d/1aNk3KHI6EVUwxMCS_TiK9yBRPLyucx63/view?usp=sharing


Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →


Iaas、Pass、Saas


Function as a Service, FaaS
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  • 就是個函式
  • 無狀態(stateless)
  • FaaS 隨叫隨開
  • 事件驅動(event-triggered)

御三家FaaS


Google Cloud Functions為例


image


image


image


🤖 客製化你的AI教學助手-蘇格拉底引導教學法 image


Vercel

image


fly.io * LINE


為何用 fly.io

Heroku宣布2022.11起開始收費


  • fly.io可部署Python服務,也可以直接自Heroku免費遷移專案


fly.io 收費標準

免費方案Hobbi
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
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


用HackMD API打造個人專屬LINE BOT助手


流程

  • 完成Fly.io基本專案
  • 完成LINE Developer基本設定
  • 修改Fly.io程式碼
  • 連結LINE與Fly.io專案

1.完成Fly.io基本專案


Fly.io 建一個新的 Flask APP 專案

Lanch an APP with Python
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

以 Python 部署 Flask APP
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →


在終端機執行以建立專案 (要先裝Git)

# 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

設定專案
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  • 可能會要同意覆蓋專案(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
    

查看狀態與部署結果
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

flyctl status
flyctl open


(最後)設定後續本機測試及開發環境

//設置環境變數`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

#新增 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 IDChannel SecretChannel Access Token

LINE Developer

  • 右上方登入(LINE帳號即可)

1.創Provider
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

2.創Channel
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

3.選MessageAPI
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →


4.建立基本資訊
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
4.建立基本資訊
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  • 同意創立後,取得Channel IDChannel Secret (在Basic Setting )

  • 取得Channel access token (在 Messaging API 分頁,按issue產生)

  • 現在有了Channel IDChannel SecretChannel Access Token
  • 等伺服器程式處理好,用webhook連結就完成了

  • 通常會把系統預設回應關掉
  • 通常會加入圖文選單

3.修改Fly.io程式碼


Line-bot-fly-flask


在hellofly修改專案檔案

修改部分檔案
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →


my_moduls/: 自製模組
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →


app.py: 主程式
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
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)

Procfile: 設定wsgi用
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
# 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

config.py: 各種Token
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
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


config.py: 各種Token
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
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專案




流程整理

Select a repo