From 1229df70b06191d384cc5252b6cd28558a82e90a Mon Sep 17 00:00:00 2001 From: Kasper Marinus Date: Wed, 8 Oct 2025 15:02:11 +0200 Subject: [PATCH] chore: filled in project structure Added some example basic files containing a functioning /message endpoint which logs the received message to INFO. ref: N25B-144 --- pyproject.toml | 3 ++ src/control_backend/agents/test_agent.py | 4 +++ .../api/v1/endpoints/message.py | 13 +++++++ src/control_backend/api/v1/endpoints/sse.py | 8 +++++ src/control_backend/api/v1/router.py | 15 ++++++++ src/control_backend/core/config.py | 11 ++++++ src/control_backend/main.py | 36 +++++++++++++++++++ src/control_backend/schemas/message.py | 4 +++ uv.lock | 6 ++++ 9 files changed, 100 insertions(+) create mode 100644 src/control_backend/agents/test_agent.py create mode 100644 src/control_backend/api/v1/endpoints/message.py create mode 100644 src/control_backend/api/v1/endpoints/sse.py create mode 100644 src/control_backend/schemas/message.py diff --git a/pyproject.toml b/pyproject.toml index 2e61334..d0a617f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,8 +9,11 @@ dependencies = [ "mlx-whisper>=0.4.3 ; sys_platform == 'darwin'", "openai-whisper>=20250625", "pyaudio>=0.2.14", + "pydantic>=2.12.0", + "pydantic-settings>=2.11.0", "pyzmq>=27.1.0", "silero-vad>=6.0.0", "spade>=4.1.0", + "torch>=2.8.0", "uvicorn>=0.37.0", ] diff --git a/src/control_backend/agents/test_agent.py b/src/control_backend/agents/test_agent.py new file mode 100644 index 0000000..7a9707b --- /dev/null +++ b/src/control_backend/agents/test_agent.py @@ -0,0 +1,4 @@ +from spade.agent import Agent + +class TestAgent(Agent): + pass \ No newline at end of file diff --git a/src/control_backend/api/v1/endpoints/message.py b/src/control_backend/api/v1/endpoints/message.py new file mode 100644 index 0000000..1ad0b65 --- /dev/null +++ b/src/control_backend/api/v1/endpoints/message.py @@ -0,0 +1,13 @@ +from fastapi import APIRouter, Request +import logging + +from control_backend.schemas.message import Message + +logger = logging.getLogger(__name__) + +router = APIRouter() + +# TODO: implement +@router.post("/message") +async def receive_message(message: Message, request: Request): + logger.info("Received message: %s", message.message) diff --git a/src/control_backend/api/v1/endpoints/sse.py b/src/control_backend/api/v1/endpoints/sse.py new file mode 100644 index 0000000..e16b7e2 --- /dev/null +++ b/src/control_backend/api/v1/endpoints/sse.py @@ -0,0 +1,8 @@ +from fastapi import APIRouter, Request + +router = APIRouter() + +# TODO: implement +@router.get("/sse") +async def sse(request: Request): + pass \ No newline at end of file diff --git a/src/control_backend/api/v1/router.py b/src/control_backend/api/v1/router.py index e69de29..559b4d3 100644 --- a/src/control_backend/api/v1/router.py +++ b/src/control_backend/api/v1/router.py @@ -0,0 +1,15 @@ +from fastapi.routing import APIRouter + +from control_backend.api.v1.endpoints import message, sse + +api_router = APIRouter() + +api_router.include_router( + message.router, + tags=["Messages"] +) + +api_router.include_router( + sse.router, + tags=["SSE"] +) diff --git a/src/control_backend/core/config.py b/src/control_backend/core/config.py index e69de29..c28c980 100644 --- a/src/control_backend/core/config.py +++ b/src/control_backend/core/config.py @@ -0,0 +1,11 @@ +from pydantic import HttpUrl +from pydantic_settings import BaseSettings, SettingsConfigDict + +class Settings(BaseSettings): + app_title: str = "PepperPlus" + + ui_url: HttpUrl = "http://locahost:5173" + + model_config = SettingsConfigDict(env_file=".env") + +settings = Settings() \ No newline at end of file diff --git a/src/control_backend/main.py b/src/control_backend/main.py index e69de29..4cd1a76 100644 --- a/src/control_backend/main.py +++ b/src/control_backend/main.py @@ -0,0 +1,36 @@ +# External imports +import contextlib +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware +import logging + +# Internal imports +from control_backend.api.v1.router import api_router +from control_backend.core.config import settings + +logger = logging.getLogger(__name__) +logging.basicConfig(level=logging.INFO) + +@contextlib.asynccontextmanager +async def lifespan(app: FastAPI): + logger.info("%s starting up.", app.title) + + yield + + logger.info("%s shutting down.", app.title) + + +# if __name__ == "__main__": +app = FastAPI(title=settings.app_title, lifespan=lifespan) +app.include_router(api_router, prefix="") # TODO: make prefix /api/v1 + +# This middleware allows other origins to communicate with us +app.add_middleware( + CORSMiddleware, # https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS + allow_origins=[settings.ui_url.unicode_string()], # address of our UI application + allow_methods=["*"], # GET, POST, etc. +) + +@app.get("/") +async def root(): + return {"status": "ok"} \ No newline at end of file diff --git a/src/control_backend/schemas/message.py b/src/control_backend/schemas/message.py new file mode 100644 index 0000000..a128ae7 --- /dev/null +++ b/src/control_backend/schemas/message.py @@ -0,0 +1,4 @@ +from pydantic import BaseModel + +class Message(BaseModel): + message: str \ No newline at end of file diff --git a/uv.lock b/uv.lock index 2c6a0a2..07bdb8f 100644 --- a/uv.lock +++ b/uv.lock @@ -1216,9 +1216,12 @@ dependencies = [ { name = "mlx-whisper", marker = "sys_platform == 'darwin'" }, { name = "openai-whisper" }, { name = "pyaudio" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, { name = "pyzmq" }, { name = "silero-vad" }, { name = "spade" }, + { name = "torch" }, { name = "uvicorn" }, ] @@ -1228,9 +1231,12 @@ requires-dist = [ { name = "mlx-whisper", marker = "sys_platform == 'darwin'", specifier = ">=0.4.3" }, { name = "openai-whisper", specifier = ">=20250625" }, { name = "pyaudio", specifier = ">=0.2.14" }, + { name = "pydantic", specifier = ">=2.12.0" }, + { name = "pydantic-settings", specifier = ">=2.11.0" }, { name = "pyzmq", specifier = ">=27.1.0" }, { name = "silero-vad", specifier = ">=6.0.0" }, { name = "spade", specifier = ">=4.1.0" }, + { name = "torch", specifier = ">=2.8.0" }, { name = "uvicorn", specifier = ">=0.37.0" }, ]