Skip to content
This repository has been archived by the owner on Jan 15, 2025. It is now read-only.

Commit

Permalink
added ai endpoint with OpenAI function handler
Browse files Browse the repository at this point in the history
  • Loading branch information
hendrikse committed Oct 29, 2024
1 parent 11da57c commit b0a385d
Show file tree
Hide file tree
Showing 7 changed files with 1,653 additions and 1,328 deletions.
137 changes: 45 additions & 92 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,84 +1,65 @@
<p>
# Bootstrap Academy AI Microservice

[![CI](https://github.com/Defelo/fastapi-template/actions/workflows/ci.yml/badge.svg)](https://github.com/Defelo/fastapi-template/actions/workflows/ci.yml)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![Maintainability](https://api.codeclimate.com/v1/badges/72080273c78701c4f0eb/maintainability)](https://codeclimate.com/github/Defelo/fastapi-template/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/72080273c78701c4f0eb/test_coverage)](https://codeclimate.com/github/Defelo/fastapi-template/test_coverage)
The official AI microservice of [Bootstrap Academy](https://bootstrap.academy/).

</p>
This microservice provides a foundational API endpoint for AI integrations, with an emphasis on extendibility. Currently, it uses OpenAI's GPT-4, but it can easily accommodate other models and providers.

# fastapi-template
If you would like to submit a bug report or feature request, or are looking for general information about the project or the publicly available instances, please refer to the [Bootstrap-Academy repository](https://github.com/Bootstrap-Academy/Bootstrap-Academy).

A template for projects that use the [FastAPI framework](https://fastapi.tiangolo.com/).
## Endpoints

## How to use this template
### POST `/api/ai`

### Choose a template branch
Accessible only to administrators with a valid API key. This endpoint takes in prompts and returns an AI-generated response.

Currently these two branches are available:
#### Request Example

- `develop`: Contains a basic FastAPI template using SQLAlchemy and aioredis, including basic logging, optional token authentication, utilities to simplify documentation creation and some demo endpoints, as well as a `Dockerfile` to create a Docker image and a GitHub Actions workflow to automatically build and push the Docker image to GitHub Container Registry.
- `users`: Contains everything included in the `develop` branch and implements basic user management functionality. This includes endpoints for user creation, session management and administration as well as features such as 2FA via TOTP, generic OAuth2 and reCAPTCHA on account creation and/or too many failed login attempts.

Replace `TEMPLATE_BRANCH` in the next section with the branch you would like to use.

### Setup repository

1. Click the [Use this template](https://github.com/Defelo/fastapi-template/generate) button to generate a new repository
2. `git clone` your new repository
3. Add this repository as a `template` remote: `git remote add template https://github.com/Defelo/fastapi-template.git && git fetch template`
4. Reset your branch to the template branch you would like to use: `git reset --hard template/TEMPLATE_BRANCH`
5. Force push your branch to GitHub: `git push -f`

To later update your repository you can just merge the template into your own branch: `git fetch template && git merge template/TEMPLATE_BRANCH`

### Customize template files

1. Adjust `name`, `description`, `authors`, `homepage` and `repository` in [pyproject.toml](https://github.com/Defelo/fastapi-template/blob/develop/pyproject.toml#L2-L9)
2. Adjust repository url in [Dockerfile](https://github.com/Defelo/fastapi-template/blob/develop/Dockerfile#L24)
3. Adjust docker image tag in [docker-compose.yml](https://github.com/Defelo/fastapi-template/blob/develop/docker-compose.yml#L5) and [.github/workflows/ci.yml](https://github.com/Defelo/fastapi-template/blob/develop/.github/workflows/ci.yml#L9)
4. (optional) Enable additional platforms for docker buildx in [.github/workflows/ci.yml](https://github.com/Defelo/fastapi-template/blob/develop/.github/workflows/ci.yml#L165-L168)
5. Enable docker push in [.github/workflows/ci.yml](https://github.com/Defelo/fastapi-template/blob/develop/.github/workflows/ci.yml#L232) by removing the `"false" #`
6. (optional) Adjust [.github/workflows/ci.yml](https://github.com/Defelo/fastapi-template/blob/develop/.github/workflows/ci.yml#L292-L304) to enable automatic deployment by sending an HTTP request to a specific url
7. (optional) If you *don't* want your dependabot pull requests to be merged automatically, remove the [.github/workflows/merge-me.yml](https://github.com/Defelo/fastapi-template/blob/develop/.github/workflows/merge-me.yml) workflow
8. (optional) If you want to automatically delete unused docker tags from GHCR:
1. Adjust repository owner and name in [.github/workflows/docker_clean.yml](https://github.com/Defelo/fastapi-template/blob/develop/.github/workflows/docker_clean.yml#L10-L11)
2. Uncomment the workflow triggers in [.github/workflows/docker_clean.yml](https://github.com/Defelo/fastapi-template/blob/develop/.github/workflows/docker_clean.yml#L4-L6)
3. Create a [personal access token](https://github.com/settings/tokens/new) with `delete:packages` permissions
4. Create a new `docker-clean` environment, allow only `develop` as deployment branch and create a `CR_PAT` secret that contains the personal access token

## Development

### Prerequisites
- [Python 3.10](https://python.org/)
- [Poetry](https://python-poetry.org/) + [poethepoet](https://pypi.org/project/poethepoet/)
- [Git](https://git-scm.com/)
- [Docker](https://www.docker.com/) + [docker-compose](https://docs.docker.com/compose/) (recommended)
- [PyCharm Community/Professional](https://www.jetbrains.com/pycharm/) (recommended)
```json
{
"system_prompt": "You are an assistant.",
"user_prompt": "What's the weather today?"
}
```

### Clone the repository
#### Response Example

#### SSH (recommended)
```bash
git clone --recursive [email protected]:Defelo/fastapi-template.git
```json
{
"output": "I am an AI model and do not have live weather data."
}
```

#### HTTPS
```bash
git clone --recursive https://github.com/Defelo/fastapi-template.git
```
## Development Setup

### Setup development environment
1. Install [Python 3.10](https://python.org/), [Poetry](https://python-poetry.org/) and [poethepoet](https://pypi.org/project/poethepoet/).
2. Clone this repository and `cd` into it.
3. Run `poe setup` to install the dependencies.
4. Run `poe api` to start the microservice. You can find the automatically generated swagger documentation on http://localhost:8001/docs.

After cloning the repository, you can setup the development environment by running the following command:
## Poetry Scripts

```bash
poe setup
poe setup # setup dependencies, .env file and pre-commit hook
poe api # start api locally
poe test # run unit tests
poe pre-commit # run pre-commit checks
poe lint # run linter
poe format # run auto formatter
poe isort # sort imports
poe black # reformat code
poe ruff # check code style
poe mypy # check typing
poe flake8 # check code style
poe coverage # run unit tests with coverage
poe alembic # use alembic to manage database migrations
poe migrate # run database migrations
poe env # show settings from .env file
poe jwt # generate a jwt with the given payload and ttl in seconds
poe check # check course definitions
poe sync_skills # push local skills to backend (deprecated)
```

This will create a virtual environment, install the dependencies, create a `.env` file and install the pre-commit hook.

### PyCharm configuration
## PyCharm configuration

Configure the Python interpreter:

Expand All @@ -93,34 +74,6 @@ Setup the run configuration:

- Click on `Add Configuration...``Add new...``Python`
- Change target from `Script path` to `Module name` and choose the `api` module
- Change the working directory to root path `Edit Configurations` `Working directory`
- Change the working directory to root path ➔ `Edit Configurations``Working directory`
- In the `EnvFile` tab add your `.env` file
- Confirm with `OK`

### Run the API

To run the api for development you can use the `api` task:

```bash
poe api
```

### Poetry Scripts

```bash
poe setup # setup dependencies, .env file and pre-commit hook
poe api # start api locally
poe test # run unit tests
poe pre-commit # run pre-commit checks
poe lint # run linter
poe format # run auto formatter
poe isort # sort imports
poe black # reformat code
poe mypy # check typing
poe flake8 # check code style
poe coverage # run unit tests with coverage
poe alembic # use alembic to manage database migrations
poe migrate # run database migrations
poe env # show settings from .env file
poe jwt # generate a jwt with the given payload and ttl in seconds
```
4 changes: 2 additions & 2 deletions api/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
logger = get_logger(__name__)

app = FastAPI(
title="FastAPI",
title="ai-ms",
description=__doc__,
version=get_version().description,
root_path=settings.root_path,
Expand All @@ -48,7 +48,7 @@ def setup_app() -> None:

if settings.sentry_dsn:
logger.debug("initializing sentry")
setup_sentry(app, settings.sentry_dsn, "FastAPI", get_version().description)
setup_sentry(app, settings.sentry_dsn, "ai-ms", get_version().description)

if settings.debug:
app.add_middleware(
Expand Down
4 changes: 2 additions & 2 deletions api/endpoints/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

from fastapi import APIRouter

from . import test
from . import ai
from .internal import INTERNAL_ROUTERS
from ..auth import internal_auth


ROUTER = APIRouter()
TAGS: list[dict[str, Any]] = []

for module in [test]:
for module in [ai]:
name = module.__name__.split(".")[-1]
router = APIRouter(tags=[name])
router.include_router(module.router)
Expand Down
25 changes: 25 additions & 0 deletions api/endpoints/ai.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from fastapi import APIRouter, Depends
from pydantic import BaseModel
from api.services.ai_handler import AIHandler
from fastapi import APIRouter, Depends, HTTPException, status
from ..utils.docs import responses
from api.auth import admin_auth, public_auth

router = APIRouter()

class AIRequest(BaseModel):
system_prompt: str
user_prompt: str

class AIResponse(BaseModel):
output: str

ai_handler = AIHandler()

@router.post("/ai", response_model=AIResponse)
async def ai_endpoint(request: AIRequest):
try:
output = ai_handler.get_ai_response(request.system_prompt, request.user_prompt)
return AIResponse(output=output)
except Exception as e:
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
22 changes: 22 additions & 0 deletions api/services/ai_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import openai

class AIHandler:
def __init__(self, provider="openai", model_name="gpt-4o-2024-08-06"):
self.provider = provider
self.model_name = model_name

def get_ai_response(self, system_prompt: str, user_prompt: str) -> str:
if self.provider == "openai":
return self._call_openai(system_prompt, user_prompt)
else:
raise NotImplementedError(f"Provider '{self.provider}' is not supported.")

def _call_openai(self, system_prompt: str, user_prompt: str) -> str:
response = openai.ChatCompletion.create(
model=self.model_name,
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
]
)
return response.choices[0].message['content']
Loading

0 comments on commit b0a385d

Please sign in to comment.