Python API For Standlone

为独立运行的脚本添加python调用接口
更方便的在jupyter中使用
pull/261/head
WSH032 2023-06-22 06:59:50 +08:00
parent 8952d83e5a
commit 5f201bea70
3 changed files with 162 additions and 31 deletions

175
app.py
View File

@ -3,14 +3,19 @@ from fastapi import FastAPI
from fastapi.responses import FileResponse
import uvicorn
import os
from scripts.iib.api import infinite_image_browsing_api
from scripts.iib.api import infinite_image_browsing_api, index_html_path
from scripts.iib.tool import cwd, get_sd_webui_conf, get_valid_img_dirs, sd_img_dirs
from scripts.iib.db.datamodel import DataBase, Image
from scripts.iib.db.update_image_data import update_image_data
import argparse
import logging
from typing import Optional, Coroutine
import asyncio
tag = "\033[31m[warn]\033[0m"
defalut_port = 8000
defalut_host = "127.0.0.1"
def normalize_paths(paths: List[str]):
"""
@ -72,34 +77,152 @@ def update_image_index(sd_webui_config: str):
print("update image index completed. ✨")
if __name__ == "__main__":
class AppUltils(object):
def __init__(self,
sd_webui_config: Optional[str] = None,
use_update_image_index: bool = False, # update_image_index会与外层函数重名
extra_paths: List[str] = [],
):
"""
sd_webui_config, type=str, default=None, help="the path to the config file"
update_image_index, action="store_true", help="update the image index"
extra_paths", nargs="+", help="extra paths to use, will be added to Quick Move.", default=[]
"""
self.sd_webui_config = sd_webui_config
self.use_update_image_index = use_update_image_index
self.extra_paths = extra_paths
def set_params(self, *args, **kwargs) -> None:
""" 改变参数与__init__的行为一致 """
self.__init__(*args, **kwargs)
@staticmethod
def async_run(app: FastAPI, port: int=defalut_port) -> Coroutine:
"""
用于从异步运行的FastAPI在jupyter notebook环境中非常有用
app为要启动的FastAPI实例
port为要启动的端口
返回协程uvicorn.Server().serve()
"""
# 不建议改成async def并且用await替换return
# 因为这样会失去对server.serve()的控制
config = uvicorn.Config(app, host=defalut_host, port=port)
server = uvicorn.Server(config)
return server.serve()
def wrap_app(self,
app: FastAPI,
) -> None:
"""
为传递的app挂载上infinite_image_browsing后端
"""
sd_webui_config = self.sd_webui_config
use_update_image_index = self.use_update_image_index
extra_paths = self.extra_paths
if sd_webui_config:
sd_webui_paths_check(sd_webui_config)
if use_update_image_index:
update_image_index(sd_webui_config)
paths_check(extra_paths)
infinite_image_browsing_api(app,
sd_webui_config=sd_webui_config,
extra_paths_cli=normalize_paths(extra_paths),
)
def get_root_browser_app(self) -> FastAPI:
"""
获取首页挂载在"/"上的infinite_image_browsing FastAPI实例
"""
app = FastAPI()
# 用于在首页显示
@app.get("/")
def index():
return FileResponse(index_html_path)
self.wrap_app(app)
return app
def setup_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="Process some integers.")
parser.add_argument("--port", type=int, help="the port to use", default=8000)
parser.add_argument("--sd_webui_config", help="the path to the config file")
parser.add_argument("--port", type=int, help="The port to use", default=defalut_port)
parser.add_argument("--sd_webui_config", type=str, default=None, help="The path to the config file")
# 弃用警告因为update_image_index会与处理函数同名
# 所以class AppUltils(object)采用的是use_update_image_index
# 有必要保证两者的一致性
parser.add_argument(
"--update_image_index", action="store_true", help="update the image index"
"--update_image_index", action="store_true", help="Update the image index. Will be deprecated. Recommend to use --use_update_image_index"
)
parser.add_argument(
"--extra_paths", nargs="+", help="extra paths to use, will be added to Quick Move.", default=[]
"--use_update_image_index", action="store_true", help="Update the image index"
)
args = parser.parse_args()
sd_webui_config = args.sd_webui_config
if sd_webui_config:
sd_webui_paths_check(sd_webui_config)
if args.update_image_index:
update_image_index(sd_webui_config)
paths_check(args.extra_paths)
app = FastAPI()
@app.get("/")
def index():
return FileResponse(os.path.join(cwd, "vue/dist/index.html"))
infinite_image_browsing_api(
None,
app,
sd_webui_config=sd_webui_config,
extra_paths_cli=normalize_paths(args.extra_paths),
parser.add_argument(
"--extra_paths", nargs="+", help="Extra paths to use, will be added to Quick Move.", default=[]
)
uvicorn.run(app, host="127.0.0.1", port=args.port)
return parser
def check_cmd_param(*args, **kwargs) -> argparse.Namespace:
"""
parser.parse_known_args()的装饰器用于报告非法参数
无任何传递将从sys.argv中解析参数
"""
cmd_param, unkonwn = parser.parse_known_args(*args, **kwargs)
if unkonwn:
logging.warning(f"{tag} Illegal args will be ingored: {unkonwn}")
if cmd_param.update_image_index:
# 弃用警告因为update_image_index会与处理函数同名
# 所以class AppUltils(object)采用的是use_update_image_index
# 有必要保证两者的一致性
logging.warning(f"{tag} --update_image_index will be deprecated, please use --use_update_image_index")
cmd_param.use_update_image_index = True
return cmd_param
def launch_app(port, *args, **kwargs) -> None:
"""
同步函数
所传入的要求参数都会传递给AppUltils()
sd_webui_config, type=str, default=None, help="the path to the config file"
update_image_index, action="store_true", help="update the image index"
extra_paths", nargs="+", help="extra paths to use, will be added to Quick Move.", default=[]
"""
app_ultils = AppUltils(*args, **kwargs)
app = app_ultils.get_root_browser_app()
uvicorn.run(app, host=defalut_host, port=port)
async def async_launch_app(port, *args, **kwargs) -> None:
"""
协程函数
所传入的要求参数都会传递给AppUltils()
sd_webui_config, type=str, default=None, help="the path to the config file"
update_image_index, action="store_true", help="update the image index"
extra_paths", nargs="+", help="extra paths to use, will be added to Quick Move.", default=[]
"""
app_ultils = AppUltils(*args, **kwargs)
app = app_ultils.get_root_browser_app()
await app_ultils.async_run(app, port=port)
parser = setup_parser()
if __name__ == "__main__":
cmd_param = check_cmd_param()
params_dict = dict(sd_webui_config = cmd_param.sd_webui_config,
use_update_image_index = cmd_param.use_update_image_index,
extra_paths = cmd_param.extra_paths,
)
app_ultils = AppUltils(**params_dict)
app = app_ultils.get_root_browser_app()
uvicorn.run(app, host=defalut_host, port=cmd_param.port)

View File

@ -38,6 +38,8 @@ from scripts.iib.db.update_image_data import update_image_data
from scripts.iib.logger import logger
index_html_path = os.path.join(cwd, "vue/dist/index.html") # 在app.py也被使用
send_img_path = {"value": ""}
mem = {
@ -60,7 +62,7 @@ async def get_token(request: Request):
raise HTTPException(status_code=401, detail="Unauthorized")
def infinite_image_browsing_api(_: Any, app: FastAPI, **kwargs):
def infinite_image_browsing_api(app: FastAPI, **kwargs):
pre = "/infinite_image_browsing"
@ -361,7 +363,7 @@ def infinite_image_browsing_api(_: Any, app: FastAPI, **kwargs):
@app.get(pre)
def index_bd():
return FileResponse(os.path.join(cwd, "vue/dist/index.html"))
return FileResponse(index_html_path)
class OpenFolderReq(BaseModel):
path: str

View File

@ -4,7 +4,10 @@ from scripts.iib.tool import locale
from scripts.iib.tool import read_info_from_image
from PIL import Image
from scripts.iib.logger import logger
from typing import Any
from fastapi import FastAPI
import gradio as gr
"""
api函数声明和启动分离方便另外一边被外部调用
@ -12,8 +15,7 @@ api函数声明和启动分离方便另外一边被外部调用
def on_ui_tabs():
import gradio as gr
with gr.Blocks(analytics_enabled=False) as view:
with gr.Row():
with gr.Column():
@ -67,6 +69,10 @@ def on_ui_tabs():
),
)
def on_app_started(_: gr.Blocks, app: FastAPI) -> None:
# 第一个参数是SD-WebUI传进来的gr.Blocks但是不需要使用
infinite_image_browsing_api(app)
script_callbacks.on_ui_tabs(on_ui_tabs)
script_callbacks.on_app_started(infinite_image_browsing_api)
script_callbacks.on_app_started(on_app_started)