-
Notifications
You must be signed in to change notification settings - Fork 417
feat(agent): bootstrap FastAPI agent service #765
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
39f6f8a
2cd3ae1
cfa20e8
a68926b
63764bb
6d00e6d
d7121eb
797fd75
4a1c06e
24c9a68
12da7ad
e61f69e
68a62a7
df3ab90
0ebb243
9ece9ed
1dfecad
34796c0
c12a572
e973355
5195c13
b530383
76d9505
7ec22a8
61759d9
38445ca
716fc44
7522328
55eede3
ff45a5e
5033074
e077e5b
b0a84fe
ff50825
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| 3.13 |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,38 @@ | ||||||||||||||||||
| FROM python:3.13-slim AS builder | ||||||||||||||||||
|
|
||||||||||||||||||
| RUN apt-get update && \ | ||||||||||||||||||
| apt-get install -y --no-install-recommends build-essential libpq-dev && \ | ||||||||||||||||||
| apt-get clean && \ | ||||||||||||||||||
| rm -rf /var/lib/apt/lists/* | ||||||||||||||||||
| RUN pip install --no-cache-dir --upgrade pyopenssl | ||||||||||||||||||
|
|
||||||||||||||||||
| COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ | ||||||||||||||||||
|
|
||||||||||||||||||
| WORKDIR /root_project | ||||||||||||||||||
|
|
||||||||||||||||||
| COPY uv.lock pyproject.toml ./ | ||||||||||||||||||
| COPY . . | ||||||||||||||||||
|
|
||||||||||||||||||
| ENV VIRTUAL_ENV=/opt/venv | ||||||||||||||||||
| RUN uv venv $VIRTUAL_ENV | ||||||||||||||||||
| ENV PATH="$VIRTUAL_ENV/bin:$PATH" | ||||||||||||||||||
| RUN uv sync --locked --no-dev | ||||||||||||||||||
|
|
||||||||||||||||||
| FROM python:3.13-slim | ||||||||||||||||||
|
|
||||||||||||||||||
| RUN apt-get update && \ | ||||||||||||||||||
| apt-get install -y --no-install-recommends libpq5 && \ | ||||||||||||||||||
| apt-get clean && \ | ||||||||||||||||||
| rm -rf /var/lib/apt/lists/* | ||||||||||||||||||
|
Comment on lines
+24
to
+27
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check if git is used in startup scripts or at runtime
rg -n --type sh -C3 'git\s' agent/scripts/Repository: the-momentum/open-wearables Length of output: 53 🏁 Script executed: #!/bin/bash
# Read the full Dockerfile to understand the build context
cat -n agent/DockerfileRepository: the-momentum/open-wearables Length of output: 1383 🏁 Script executed: #!/bin/bash
# Check for git-based dependencies in pyproject.toml or requirements files
fd -e toml -e txt -e lock | grep -E '(pyproject|requirements|uv\.lock)' | head -20Repository: the-momentum/open-wearables Length of output: 201 🏁 Script executed: #!/bin/bash
# Search for pygentic-ai and how it's referenced
rg -n 'pygentic-ai' --max-count 20Repository: the-momentum/open-wearables Length of output: 1769 Remove The 🗑️ Proposed fix to remove git from runtime RUN apt-get update && \
- apt-get install -y --no-install-recommends libpq5 git && \
+ apt-get install -y --no-install-recommends libpq5 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||
|
|
||||||||||||||||||
| WORKDIR /root_project | ||||||||||||||||||
|
|
||||||||||||||||||
| COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ | ||||||||||||||||||
|
|
||||||||||||||||||
| COPY --from=builder /opt/venv /opt/venv | ||||||||||||||||||
| COPY --from=builder /root_project /root_project | ||||||||||||||||||
| ENV VIRTUAL_ENV=/opt/venv | ||||||||||||||||||
| ENV PATH="/opt/venv/bin:$PATH" | ||||||||||||||||||
| ENV UV_PROJECT_ENVIRONMENT=/opt/venv | ||||||||||||||||||
|
|
||||||||||||||||||
| EXPOSE 8000 | ||||||||||||||||||
|
coderabbitai[bot] marked this conversation as resolved.
|
||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| # API | ||
|
|
||
| A FastAPI application with PostgreSQL database support, containerized with Docker. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - Docker and Docker Compose | ||
| - Python 3.12+ (for local development) | ||
|
|
||
| ## Setup | ||
|
|
||
| 1. **Create environment file** | ||
| ```bash | ||
| cp ./config/.env.example ./config/.env | ||
| # Edit .env file with your configuration | ||
| ``` | ||
|
|
||
| ## Running the Application | ||
|
|
||
| ### Docker (Recommended) | ||
|
|
||
| ```bash | ||
| # Start services | ||
| docker compose up -d | ||
|
|
||
| # Create migration | ||
| docker compose exec app uv run alembic revision --autogenerate -m "Description" | ||
|
|
||
| # Run migrations | ||
| docker compose exec app uv run alembic upgrade head | ||
| ``` | ||
|
|
||
| ### Local Development | ||
|
|
||
| ```bash | ||
| # Install dependencies | ||
| uv sync | ||
|
|
||
| # Start PostgreSQL locally | ||
|
|
||
| # Create migration | ||
| uv run alembic revision --autogenerate -m "Description" | ||
|
|
||
| # Run migrations | ||
| uv run alembic upgrade head | ||
|
|
||
| # Start development server | ||
| uv run fastapi run app/main.py --reload | ||
| ``` | ||
|
|
||
| ### Access the application | ||
| - API: http://localhost:8000 | ||
| - Swagger: http://localhost:8000/docs | ||
|
|
||
| --- | ||
|
|
||
| This project was generated from the [Python AI Kit](https://github.com/the-momentum/python-ai-kit). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| [alembic] | ||
| script_location = migrations | ||
| prepend_sys_path = . | ||
| version_path_separator = os | ||
| sqlalchemy.url = | ||
|
|
||
| [loggers] | ||
| keys = root,sqlalchemy,alembic | ||
|
|
||
| [handlers] | ||
| keys = console | ||
|
|
||
| [formatters] | ||
| keys = generic | ||
|
|
||
| [logger_root] | ||
| level = WARN | ||
| handlers = console | ||
| qualname = | ||
|
|
||
| [logger_sqlalchemy] | ||
| level = WARN | ||
| handlers = | ||
| qualname = sqlalchemy.engine | ||
|
|
||
| [logger_alembic] | ||
| level = INFO | ||
| handlers = | ||
| qualname = alembic | ||
|
|
||
| [handler_console] | ||
| class = StreamHandler | ||
| args = (sys.stderr,) | ||
| level = NOTSET | ||
| formatter = generic | ||
|
|
||
| [formatter_generic] | ||
| format = %(levelname)-5.5s [%(name)s] %(message)s | ||
| datefmt = %H:%M:%S |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| from fastapi import APIRouter | ||
|
|
||
| from app.api.routes.v1 import v1_router | ||
|
|
||
| head_router = APIRouter() | ||
| head_router.include_router(v1_router) | ||
|
|
||
| __all__ = ["head_router"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| from fastapi import APIRouter | ||
|
|
||
| from app.api.routes.v1.chat import router as chat_router | ||
| from app.api.routes.v1.session import router as session_router | ||
|
|
||
| v1_router = APIRouter() | ||
| v1_router.include_router(session_router) | ||
| v1_router.include_router(chat_router) | ||
|
|
||
| __all__ = ["v1_router"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| from __future__ import annotations | ||
|
|
||
| import logging | ||
| from typing import Annotated | ||
| from uuid import UUID | ||
|
|
||
| from fastapi import APIRouter, Depends | ||
|
|
||
| from app.integrations.celery.tasks.process_message import process_message | ||
| from app.schemas.chat import ChatRequest, ChatTaskResponse | ||
| from app.services.chat_session import ChatSessionService | ||
| from app.utils.auth import CurrentUserId | ||
|
|
||
| router = APIRouter(prefix="/chat", tags=["chat"]) | ||
| logger = logging.getLogger(__name__) | ||
|
|
||
| ChatSessionServiceDep = Annotated[ChatSessionService, Depends(ChatSessionService)] | ||
|
|
||
|
|
||
| @router.post("/{session_id}") | ||
| async def send_message( | ||
| session_id: UUID, | ||
| body: ChatRequest, | ||
| current_user: CurrentUserId, | ||
| service: ChatSessionServiceDep, | ||
| ) -> ChatTaskResponse: | ||
| session, conversation = await service.get_active_session(session_id, current_user) | ||
|
|
||
| task = process_message.delay( | ||
| session_id=str(session.id), | ||
| conversation_id=str(conversation.id), | ||
| message=body.message, | ||
| callback_url=str(body.callback_url), | ||
| ) | ||
|
|
||
| logger.info(f"Queued task {task.id} for session {session.id}") | ||
| return ChatTaskResponse(task_id=task.id) | ||
|
|
||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| from __future__ import annotations | ||
|
|
||
| import logging | ||
| from typing import Annotated | ||
| from uuid import UUID | ||
|
|
||
| from fastapi import APIRouter, Depends | ||
| from starlette import status | ||
|
|
||
| from app.schemas.session import SessionCreateResponse, SessionDeactivateResponse, SessionRequest | ||
| from app.services.chat_session import ChatSessionService | ||
| from app.utils.auth import CurrentUserId | ||
|
|
||
| router = APIRouter(prefix="/session", tags=["session"]) | ||
| logger = logging.getLogger(__name__) | ||
|
|
||
| ChatSessionServiceDep = Annotated[ChatSessionService, Depends(ChatSessionService)] | ||
|
|
||
|
|
||
| @router.post("", status_code=status.HTTP_201_CREATED) | ||
| async def create_or_get_session( | ||
| body: SessionRequest, | ||
| current_user: CurrentUserId, | ||
| service: ChatSessionServiceDep, | ||
| ) -> SessionCreateResponse: | ||
| session, conversation = await service.upsert_session(current_user, body.session_id) | ||
| return SessionCreateResponse( | ||
| session_id=session.id, | ||
| conversation_id=conversation.id, | ||
| created_at=session.created_at, | ||
| ) | ||
|
|
||
|
|
||
| @router.patch("/{session_id}") | ||
| async def deactivate_session( | ||
| session_id: UUID, | ||
| current_user: CurrentUserId, | ||
| service: ChatSessionServiceDep, | ||
| ) -> SessionDeactivateResponse: | ||
| session = await service.deactivate_session(session_id, current_user) | ||
| return SessionDeactivateResponse(session_id=session.id) |
Uh oh!
There was an error while loading. Please reload this page.