This repository has been archived by the owner on Jan 15, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added ai endpoint with OpenAI function handler
- Loading branch information
Showing
7 changed files
with
1,653 additions
and
1,328 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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: | ||
|
||
|
@@ -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 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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'] |
Oops, something went wrong.