2024年4月14日
目次
以前は、『Flask』を使っていまふたが、
フロントエンドに『Typescript』を使い始めて、
バックエンドでも『型』が使えた方がしっくりくるな~と、
『FastAPI』を使い始めまふた。
今回は、バックエンドの『FastAPI』の実装方法でふ。
コード全般は、下記になりまふ。
https://github.com/supplepentan/penta_sample_fastapi_vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
import os import shutil from io import BytesIO import uvicorn from fastapi import FastAPI, UploadFile from fastapi.params import File from fastapi.responses import FileResponse from fastapi.staticfiles import StaticFiles from PIL import Image from starlette.middleware.cors import CORSMiddleware from starlette.requests import Request from starlette.templating import Jinja2Templates PATH_UPLOAD_FOLDER = "./upload" PATH_OUTPUT_FOLDER = "./output" PATH_INPUT_IMAGE = os.path.join(PATH_UPLOAD_FOLDER, "input.png") PATH_OUTPUT_IMAGE = os.path.join(PATH_OUTPUT_FOLDER, "output.png") app = FastAPI(title="さぷりぺんたんのさんぷる", description="画像をグレイスケールにするよ", version="1.0") import mimetypes mimetypes.init() mimetypes.add_type("application/javascript", ".js") #: Configure CORS origins = ["http://localhost:8080", "http://127.0.0.1:5173"] app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.mount("/static", StaticFiles(directory="./templates/static"), name="static") templates = Jinja2Templates(directory="./templates/") @app.get("/") def index(request: Request): if os.path.exists(PATH_UPLOAD_FOLDER): shutil.rmtree(PATH_UPLOAD_FOLDER) os.makedirs(PATH_UPLOAD_FOLDER) if os.path.exists(PATH_OUTPUT_FOLDER): shutil.rmtree(PATH_OUTPUT_FOLDER) os.makedirs(PATH_OUTPUT_FOLDER) return templates.TemplateResponse("index.html", {"request": request}) @app.post("/upload") async def index(file: UploadFile = File(...)): contents = await file.read() input_image = Image.open(BytesIO(contents)).convert("RGB") input_image.save(PATH_INPUT_IMAGE) output_image = input_image.convert("L") output_image.save(PATH_OUTPUT_IMAGE) output_finlename = os.path.basename(PATH_OUTPUT_IMAGE) response = FileResponse(path=PATH_OUTPUT_IMAGE, filename=output_finlename) return response if __name__ == "__main__": uvicorn.main(app=app) |
『poetry』を使って、モジュールをインストールしまふ。
1 |
poetry add fastapi "uvicorn[standard]" Jinja2 Pillow python-multipart |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import os import shutil from io import BytesIO import uvicorn from fastapi import FastAPI, UploadFile from fastapi.params import File from fastapi.responses import FileResponse from fastapi.staticfiles import StaticFiles from PIL import Image from starlette.middleware.cors import CORSMiddleware from starlette.requests import Request from starlette.templating import Jinja2Templates |
下記の表記で、自作javascriptを読み込ませることができまふ。
1 2 3 4 |
import mimetypes mimetypes.init() mimetypes.add_type("application/javascript", ".js") |
開発環境では、フロントエンド(Vue.js)とバックエンド(FlaskやFastAPI)を同時にサーバーを立てることになりまふ。
その場合、フロントエンドからバックエンドにAPIをたたくときに、
なにも対策をしなければ、CORSエラーが出てしまいまふ。
なので、下記のCORS対策をしまふ。
先のフロントエンドのViteが、
『http://127.0.0.1:5173』を使いまふので、
originsに加えまふ。
『http://localhost:8080』は、FastAPIの仮想サーバーのアドレスでふ。
1 2 3 4 5 6 7 8 9 10 11 |
origins = ["http://localhost:8080", "http://127.0.0.1:5173"] app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.mount("/static", StaticFiles(directory="./templates/static"), name="static") templates = Jinja2Templates(directory="./templates/") |
1 2 |
app.mount("/static", StaticFiles(directory="./templates/static"), name="static") templates = Jinja2Templates(directory="./templates/") |
ホーム画面でふ。
1 2 3 4 5 6 7 8 9 |
@app.get("/") def index(request: Request): if os.path.exists(PATH_UPLOAD_FOLDER): shutil.rmtree(PATH_UPLOAD_FOLDER) os.makedirs(PATH_UPLOAD_FOLDER) if os.path.exists(PATH_OUTPUT_FOLDER): shutil.rmtree(PATH_OUTPUT_FOLDER) os.makedirs(PATH_OUTPUT_FOLDER) return templates.TemplateResponse("index.html", {"request": request}) |
今回は、『Pillow』でアップロードされた画像をグレースケールにしてリターンするようにしてありまふ。
画像系AIで遊ぶときは、『Pillow』で画像を読み込み、
これをAIコードに渡し、処理後の画像をフロントへリターンする作りにしておりまふ。
1 2 3 4 5 6 7 8 9 10 |
@app.post("/upload") async def index(file: UploadFile = File(...)): contents = await file.read() input_image = Image.open(BytesIO(contents)).convert("RGB") input_image.save(PATH_INPUT_IMAGE) output_image = input_image.convert("L") output_image.save(PATH_OUTPUT_IMAGE) output_finlename = os.path.basename(PATH_OUTPUT_IMAGE) response = FileResponse(path=PATH_OUTPUT_IMAGE, filename=output_finlename) return response |
1 2 |
if __name__ == "__main__": uvicorn.main(app=app) |
1 |
poetry run uvicorn main:app --reload |
frontで作成したビルドファイルを下記のフォルダに配置します。
index.htmlのcssとjsを読み込む部分をマスタッシュ構文に書き換えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Vite + Vue + TS</title> <script type="module" crossorigin src="{{ url_for('static', path='/index.c9a0e7a1.js') }}"></script> <link rel="stylesheet" href="{{ url_for('static', path='/index.66df8b22.css') }}"> </head> <body> <div id="app"></div> </body> </html> |
関連記事