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

Commit b0a385d

Browse files
committed
added ai endpoint with OpenAI function handler
1 parent 11da57c commit b0a385d

File tree

7 files changed

+1653
-1328
lines changed

7 files changed

+1653
-1328
lines changed

README.md

Lines changed: 45 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,65 @@
1-
<p>
1+
# Bootstrap Academy AI Microservice
22

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

8-
</p>
5+
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.
96

10-
# fastapi-template
7+
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).
118

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

14-
## How to use this template
11+
### POST `/api/ai`
1512

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

18-
Currently these two branches are available:
15+
#### Request Example
1916

20-
- `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.
21-
- `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.
22-
23-
Replace `TEMPLATE_BRANCH` in the next section with the branch you would like to use.
24-
25-
### Setup repository
26-
27-
1. Click the [Use this template](https://github.com/Defelo/fastapi-template/generate) button to generate a new repository
28-
2. `git clone` your new repository
29-
3. Add this repository as a `template` remote: `git remote add template https://github.com/Defelo/fastapi-template.git && git fetch template`
30-
4. Reset your branch to the template branch you would like to use: `git reset --hard template/TEMPLATE_BRANCH`
31-
5. Force push your branch to GitHub: `git push -f`
32-
33-
To later update your repository you can just merge the template into your own branch: `git fetch template && git merge template/TEMPLATE_BRANCH`
34-
35-
### Customize template files
36-
37-
1. Adjust `name`, `description`, `authors`, `homepage` and `repository` in [pyproject.toml](https://github.com/Defelo/fastapi-template/blob/develop/pyproject.toml#L2-L9)
38-
2. Adjust repository url in [Dockerfile](https://github.com/Defelo/fastapi-template/blob/develop/Dockerfile#L24)
39-
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)
40-
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)
41-
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" #`
42-
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
43-
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
44-
8. (optional) If you want to automatically delete unused docker tags from GHCR:
45-
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)
46-
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)
47-
3. Create a [personal access token](https://github.com/settings/tokens/new) with `delete:packages` permissions
48-
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
49-
50-
## Development
51-
52-
### Prerequisites
53-
- [Python 3.10](https://python.org/)
54-
- [Poetry](https://python-poetry.org/) + [poethepoet](https://pypi.org/project/poethepoet/)
55-
- [Git](https://git-scm.com/)
56-
- [Docker](https://www.docker.com/) + [docker-compose](https://docs.docker.com/compose/) (recommended)
57-
- [PyCharm Community/Professional](https://www.jetbrains.com/pycharm/) (recommended)
17+
```json
18+
{
19+
"system_prompt": "You are an assistant.",
20+
"user_prompt": "What's the weather today?"
21+
}
22+
```
5823

59-
### Clone the repository
24+
#### Response Example
6025

61-
#### SSH (recommended)
62-
```bash
63-
git clone --recursive [email protected]:Defelo/fastapi-template.git
26+
```json
27+
{
28+
"output": "I am an AI model and do not have live weather data."
29+
}
6430
```
6531

66-
#### HTTPS
67-
```bash
68-
git clone --recursive https://github.com/Defelo/fastapi-template.git
69-
```
32+
## Development Setup
7033

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

73-
After cloning the repository, you can setup the development environment by running the following command:
39+
## Poetry Scripts
7440

7541
```bash
76-
poe setup
42+
poe setup # setup dependencies, .env file and pre-commit hook
43+
poe api # start api locally
44+
poe test # run unit tests
45+
poe pre-commit # run pre-commit checks
46+
poe lint # run linter
47+
poe format # run auto formatter
48+
poe isort # sort imports
49+
poe black # reformat code
50+
poe ruff # check code style
51+
poe mypy # check typing
52+
poe flake8 # check code style
53+
poe coverage # run unit tests with coverage
54+
poe alembic # use alembic to manage database migrations
55+
poe migrate # run database migrations
56+
poe env # show settings from .env file
57+
poe jwt # generate a jwt with the given payload and ttl in seconds
58+
poe check # check course definitions
59+
poe sync_skills # push local skills to backend (deprecated)
7760
```
7861

79-
This will create a virtual environment, install the dependencies, create a `.env` file and install the pre-commit hook.
80-
81-
### PyCharm configuration
62+
## PyCharm configuration
8263

8364
Configure the Python interpreter:
8465

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

9475
- Click on `Add Configuration...``Add new...``Python`
9576
- Change target from `Script path` to `Module name` and choose the `api` module
96-
- Change the working directory to root path `Edit Configurations` `Working directory`
77+
- Change the working directory to root path ➔ `Edit Configurations``Working directory`
9778
- In the `EnvFile` tab add your `.env` file
9879
- Confirm with `OK`
99-
100-
### Run the API
101-
102-
To run the api for development you can use the `api` task:
103-
104-
```bash
105-
poe api
106-
```
107-
108-
### Poetry Scripts
109-
110-
```bash
111-
poe setup # setup dependencies, .env file and pre-commit hook
112-
poe api # start api locally
113-
poe test # run unit tests
114-
poe pre-commit # run pre-commit checks
115-
poe lint # run linter
116-
poe format # run auto formatter
117-
poe isort # sort imports
118-
poe black # reformat code
119-
poe mypy # check typing
120-
poe flake8 # check code style
121-
poe coverage # run unit tests with coverage
122-
poe alembic # use alembic to manage database migrations
123-
poe migrate # run database migrations
124-
poe env # show settings from .env file
125-
poe jwt # generate a jwt with the given payload and ttl in seconds
126-
```

api/app.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
logger = get_logger(__name__)
3030

3131
app = FastAPI(
32-
title="FastAPI",
32+
title="ai-ms",
3333
description=__doc__,
3434
version=get_version().description,
3535
root_path=settings.root_path,
@@ -48,7 +48,7 @@ def setup_app() -> None:
4848

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

5353
if settings.debug:
5454
app.add_middleware(

api/endpoints/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22

33
from fastapi import APIRouter
44

5-
from . import test
5+
from . import ai
66
from .internal import INTERNAL_ROUTERS
77
from ..auth import internal_auth
88

99

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

13-
for module in [test]:
13+
for module in [ai]:
1414
name = module.__name__.split(".")[-1]
1515
router = APIRouter(tags=[name])
1616
router.include_router(module.router)

api/endpoints/ai.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from fastapi import APIRouter, Depends
2+
from pydantic import BaseModel
3+
from api.services.ai_handler import AIHandler
4+
from fastapi import APIRouter, Depends, HTTPException, status
5+
from ..utils.docs import responses
6+
from api.auth import admin_auth, public_auth
7+
8+
router = APIRouter()
9+
10+
class AIRequest(BaseModel):
11+
system_prompt: str
12+
user_prompt: str
13+
14+
class AIResponse(BaseModel):
15+
output: str
16+
17+
ai_handler = AIHandler()
18+
19+
@router.post("/ai", response_model=AIResponse)
20+
async def ai_endpoint(request: AIRequest):
21+
try:
22+
output = ai_handler.get_ai_response(request.system_prompt, request.user_prompt)
23+
return AIResponse(output=output)
24+
except Exception as e:
25+
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))

api/services/ai_handler.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import openai
2+
3+
class AIHandler:
4+
def __init__(self, provider="openai", model_name="gpt-4o-2024-08-06"):
5+
self.provider = provider
6+
self.model_name = model_name
7+
8+
def get_ai_response(self, system_prompt: str, user_prompt: str) -> str:
9+
if self.provider == "openai":
10+
return self._call_openai(system_prompt, user_prompt)
11+
else:
12+
raise NotImplementedError(f"Provider '{self.provider}' is not supported.")
13+
14+
def _call_openai(self, system_prompt: str, user_prompt: str) -> str:
15+
response = openai.ChatCompletion.create(
16+
model=self.model_name,
17+
messages=[
18+
{"role": "system", "content": system_prompt},
19+
{"role": "user", "content": user_prompt}
20+
]
21+
)
22+
return response.choices[0].message['content']

0 commit comments

Comments
 (0)