93 lines
2.5 KiB
Python
93 lines
2.5 KiB
Python
#!/usr/bin/env python3
|
|
"""ai-image 入口:REST + Web 控制台 + MCP。
|
|
|
|
启动方式:
|
|
python main.py # Web + REST + MCP(http) 同端口
|
|
python main.py --stdio # 仅 MCP stdio(给 MCP 客户端当子进程用)
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import contextlib
|
|
|
|
from fastapi import FastAPI
|
|
from fastapi.staticfiles import StaticFiles
|
|
|
|
from app import config, db
|
|
from app.mcp_server import build_http_app
|
|
from app.routers import api_gallery, api_generate, api_models, api_providers, api_skills
|
|
|
|
config.ensure_dirs()
|
|
db.init_db()
|
|
|
|
mcp_app = build_http_app(path="/mcp")
|
|
|
|
|
|
@contextlib.asynccontextmanager
|
|
async def lifespan(_: FastAPI):
|
|
async with mcp_app.lifespan(mcp_app):
|
|
yield
|
|
|
|
|
|
app = FastAPI(title="ai-image", version="2.0.0", lifespan=lifespan)
|
|
|
|
app.include_router(api_providers.router)
|
|
app.include_router(api_models.router)
|
|
app.include_router(api_generate.router)
|
|
app.include_router(api_gallery.router)
|
|
app.include_router(api_skills.router)
|
|
|
|
|
|
@app.get("/health")
|
|
def health():
|
|
return {"status": "ok", "output_dir": str(config.OUTPUT_DIR)}
|
|
|
|
|
|
app.mount("/output", StaticFiles(directory=config.OUTPUT_DIR), name="output")
|
|
app.mount("/", StaticFiles(directory=config.WEB_DIR, html=True), name="web")
|
|
|
|
|
|
class RootDispatcher:
|
|
"""按路径前缀把请求分发给 MCP 或 Web 应用。
|
|
|
|
Web 静态资源挂在根路径,MCP 需要独占 /mcp,因此不能靠 mount 处理。
|
|
"""
|
|
|
|
def __init__(self, web_app, mcp_asgi, prefix: str = "/mcp"):
|
|
self.web_app = web_app
|
|
self.mcp_asgi = mcp_asgi
|
|
self.prefix = prefix
|
|
|
|
async def __call__(self, scope, receive, send):
|
|
path = scope.get("path", "")
|
|
if scope["type"] == "http" and (path == self.prefix or path.startswith(self.prefix + "/")):
|
|
await self.mcp_asgi(scope, receive, send)
|
|
else:
|
|
await self.web_app(scope, receive, send)
|
|
|
|
|
|
dispatcher = RootDispatcher(app, mcp_app)
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser(description="ai-image 服务")
|
|
parser.add_argument("--stdio", action="store_true", help="以 MCP stdio 模式运行")
|
|
parser.add_argument("--host", default=config.HOST)
|
|
parser.add_argument("--port", type=int, default=config.PORT)
|
|
args = parser.parse_args()
|
|
|
|
if args.stdio:
|
|
from app.mcp_server import mcp
|
|
|
|
mcp.run()
|
|
return
|
|
|
|
import uvicorn
|
|
|
|
uvicorn.run(dispatcher, host=args.host, port=args.port)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|