Building a DigitalOcean OpenAI API Proxy
Update: Fabric, the OpenAI proxy discussed below is now public! Definitely worth a peek :)
I recently took Daniel Miessler's Augmented course and thought I'd take a stab at implementing the OpenAI API proxy he discussed. And since I like playing with the plumbing rather than operating it on a long-term basis I wanted to do something other than just host it on a VPS somewhere.
I'd initially planned on building my proxy using a serverless architecture, but the entry-level tiers for the providers I looked at all timeouts in the 10-30s range, which often isn't enough time for OpenAI to work its magic.
I eventually settled on DigitalOcean's App platform. This is sort of halfway between a VPS and a serverless function. You write code for Flask the same way you would normally, but then you upload it to the platform and don't have to worry about the base OS. Score!
The rest of this post details the process required to build our own authenticated API that hosts Daniel's useful ExtWis tool and a CLI to go along with it.
Note: This is a proof-of-concept project that is optimized for quick and simple deployment. There are likely a few unhandled bugs and a bucketful of improvements to be made. Hopefully it does a good enough job getting you acquainted with the various pieces that you can take what I've built and run with it!
The full code can be found here.
Pre-Requisites
There are a few things you need to set up before getting into it.
- GitHub Account - You can use GitLab, but I don't so you'll need to translate.
- A Linux-y Shell - You can probably do this with PowerShell, but again - translation.
- Python - A modern version of Python 3 with pipx installed.
- OpenAI API Key - Needed for our API calls.
- DigitalOcean account - For obvious reasons. If you don't have one, feel free to use my referral code to get a free $200 credit.
- Also, install and configure doctl.
Project Layout
This is the project layout we're working towards. I'll explain this in subsequent sections:
|
|
GitHub Configuration
DigitalOcean Apps build when you push to GitHub (or GitLab, weirdos) by default, so our first step is going to be configuring one of those.
- Log in to GitHub and create the repository.
- Make sure you can clone it locally.
- Log into DigitalOcean and then give it read/write access to that repository so it can do it's buildy magic.
- Do a little dance.
Server
We're going to start with the server configuration. We'll cover both creating the Flask API server and deploying it to the DigitalOcean App platform.
Flask Configuration
We're using Flask because it's quick and easy to set up and is more than capable of hosting our APIs.
The Flask configuration lives in app.py
:
|
|
This looks pretty minimal because it is. The code defines a single API route, /extwis
, accessible via the POST
method. The @token_required
line is called a decorator, and this one ensures that any incoming requests have a valid token provided in the Authorization
header. The logic is implemented in util/auth.py
:
|
|
Next we have the code that loads our prompt from disk and sends it to OpenAI. This is copied right out of OpenAI's documentation, more or less verbatim.
Let's take a look at what it does:
|
|
The from api.extwis import extwis
line imports the functions stored api/extwis/extwis.py
, which we then call with extwis.send()
. The system
prompt is loaded from system.md
(grab a copy here), and the user's input is sent as the user
prompt. The output is returned to the calling function, route_extwis()
, and then back to the user.
And that's basically it for Flask! You should be able to run the server locally doing the following:
|
|
You can call the API using httpie:
|
|
Let's launch this sucker into the cloud.
DigitalOcean App Deploy
For a platform that was released in 2020, there is a dearth of documentation available about this product. Luckily, there isn't a whole lot to deploying app so I was able to cobble together a working configuration.
I'm going to focus on using the doctl
CLI tool to deploy things since that's where I tend to spend most of my time, but you can definitely do this using the UI if you prefer lots of unnecessary clicking.
To start, we're going to define the App Spec. This is a YAML file stored in .do/app.yml
that handles all the platform-specific configuration:
|
|
Here's some notes about the values
APPNAME
- The name your app will appear under in the DigitalOcean control panel and in the default app URL.REPONAME
- Your GitHub organization and repository. Should be something likeyourname/somerepo
.
With the above values configured, it's time to push this all up to GitHub:
|
|
Finally, we create the App:
|
|
Browse to the DigitalOcean Apps panel and see what ye hath wrought! If all goes well, your app should go from Building to Deploying!
Our next step is configuring the environment variables needed by the application for authentication:
- Click on your app name.
- Click Settings.
- Beside App-Level Environment Variables, click Edit.
- Add the following:
OPENAI_API_KEY
- Your OpenAI API key.API_SECRET
- The API secret you created.
- Click Save.
You can get the URL from the UI or by running:
|
|
You can test whether your API is alive the same way you did earlier with your local Flask server:
|
|
Huzzah! Let's make it a bit easier to use this API from our desktop.
Client
Compared to the server, the client is dead simple.
|
|
All of the client logic is stored in client/extwis/main.py
:
|
|
This takes input on stdin
, attaches an authorization header, and sends it to our API. Ezpz.
Requirements live in client/extwis/requirements.txt
:
requests
click
And to make life easier for us on the CLI, we're also going to define client/extwis/setup.py
:
|
|
This is mostly straightforward, but one area that took me a minute to understand was the entry_points
block. This is basically saying “map the extwis
command to the main
function of extwis/main.py
”.
With these pieces in place, we can finally install our CLI tool using pipx
:
|
|
Conclusion
The above steps should give you a halfway decent understanding of what we're doing. Extending the APIs just involves creating and incorporating additional configuration under client/
and server/
. Happy hacking!