"""Standalone FastAPI server for Memory System API.""" from __future__ import annotations import logging from fastapi import FastAPI, Request, Response from fastapi.middleware.cors import CORSMiddleware from .api import router from .config import Config, load_config, set_config request_logger = logging.getLogger("memory_system_api.requests") app = FastAPI(title="Memory System API", version="0.1.0") app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) @app.middleware("http") async def log_request_and_response(request: Request, call_next): request_body = await request.body() request_logger.info( "request %s %s body=%s", request.method, _path_with_query(request), _body_for_log(request_body), ) async def receive(): return {"type": "http.request", "body": request_body, "more_body": False} response = await call_next(Request(request.scope, receive)) response_body = b"" async for chunk in response.body_iterator: response_body += chunk request_logger.info( "response %s %s status=%s body=%s", request.method, _path_with_query(request), response.status_code, _body_for_log(response_body), ) return Response( content=response_body, status_code=response.status_code, headers=dict(response.headers), media_type=response.media_type, background=response.background, ) app.include_router(router) def create_app(config: Config | None = None) -> FastAPI: if config: set_config(config) return app def _path_with_query(request: Request) -> str: query = request.url.query return f"{request.url.path}?{query}" if query else request.url.path def _body_for_log(body: bytes) -> str: if not body: return "" return body.decode("utf-8", errors="replace") def main() -> None: import argparse import uvicorn parser = argparse.ArgumentParser(description="Memory System API") parser.add_argument("--config", default="config.yaml", help="Config file path") parser.add_argument("--host", default=None, help="Bind host") parser.add_argument("--port", type=int, default=None, help="Bind port") args = parser.parse_args() config = load_config(args.config) if args.host: config.server.host = args.host if args.port: config.server.port = args.port set_config(config) logging.basicConfig(level=config.logging.level.upper(), format=config.logging.format) uvicorn.run(app, host=config.server.host, port=config.server.port, log_level=config.logging.level.lower()) if __name__ == "__main__": main()