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
在終端機執行以建立專案 (要先裝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
? 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
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
flyctl secrets set DATABASE_URL= ....
#取消 secrets
flyctl secrets unset DATABASE_URL= ....
#列出 secrets list
flyctl secrets list
(建立程式可控的 LINE@ 服務)
Channel ID
、 Channel Secret
、 Channel Access Token
。![]() |
![]() |
---|
![]() |
![]() |
---|
![]() |
![]() |
---|
![]() |
![]() |
---|
Channel ID
、 Channel Secret
、 Channel Access Token
。在hellofly修改專案檔案
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"") 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)
# 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
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
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