feathers-openai
NOTE: This library is new and APIs may change as features stablize.
Introduction
This library enables a series of FeathersJS services that map to the entities and routes of the OpenAI API.
By wrapping the API in a set of FeathersJS services, developers can quickly integrate any subset of the OpenAI API into their FeathersJS application. This enables the developer to log, manipulate, wrap hooks around, and make direct or indirect calls to the API.
Motivation
Exposing OpenAI within a secure enterprise environment comes with inherent risk, given the likely high volume of text data that leaves your system. By consolidating OpenAI behind a Feathers service, we can get the benefits of both a secure proxy and the control that comes with individualized authentication and query filtering. Feathers-openai can be both a quick way to integrate OpenAI into an application as well as a quick way to scale an enterprise gateway to the OpenAI API with all of the benefits of FeathersJS baked in (Auth mgmt, API key mgmt, custom mutations and resolvers, etc.)
Features
- All OpenAI routes get their own service (e.g.
openai/embeddings
) - Nested routes are included (e.g.
openai/fine-tunes/:id/cancel
) - Allows prefixing to prevent route overwriting (
/my-openai-prefix/models
) - All OpenAI Services can be extended with normal hooks
- Allows for uploads via
multer
- Light validation via TypeBox on all
create
calls. - Can disable individual services via configuration
Compatability
This library and the services included are tested against REST APIs for Feathers v5. The examples below demonstrate the use of uploads for KoaJS only, though Express is probably very similar.
Additional testing and PRs are welcome.
feathers | v5 | v4 | v3 |
---|---|---|---|
express | ✅ | ❔ | ❔ |
koa | ✅ | ❔ | ❔ |
primus | ❔ | ❔ | ❔ |
socket.io | ❔ | ❔ | ❔ |
Todo
- - Integrate all routes with FeathersJS
- - Incorporate uploads via buffer streams
- - Document multer example with KoaJS
- - Document multer example with ExpressJS
- - Testing for uploads
- - Testing for configuration
- - Testing for sample services
- - Expand testing to cover all services
NOTE: PRs are welcome!
Installation
To install the services, add the library as a dependency.
npm install --save feathers-openai multer @koa/multer
In your app.js
file, add the following middleware calls:
import koamulter from '@koa/multer';
import { openaiMulter, openai } from 'feathers-openai';
app.use(koamulter().any());
app.use(openaiMulter);
The koamulter
captures multi-part form uploads to your endpoints. The openaiMulter
appends the file(s) to the ctx.feathers
object, making the buffers accessible within the hook and service params
. The multer
library or equivalent is required by koamulter
.
In your src/services/index.js
add the following:
import { openai } from 'feathers-openai'
export const services = (app) => {
app.configure(openai('openai'))
// ... other services
}
Configuration
API Key in [env].json
You must add your API key in your /config/[env].json
file.
{
"openai":"sk-XXXXXXXXXXXXXXXXXXXXXX"
}
Service Options:
prefix
(optional, default:openai
) - The prefix added to every OpenAI service route. This allows you to nest the services so that their common names (i.e.model
, etc.) don't overwrite your core application services. The default setting will result in routes likeopenai/models
andopenai/fine-tunes
.allowedEntities
(optional, default: all). This option allows you to disable and prevent the loading of any of the OpenAI API routes and entities. It takes an array of entity names. For example, settingallowedEntities=['models']
would enable only theopenai/models
service. This list of services are:models
edits
completions
images/generations
images/edits
images/variations
fine-tunes
embeddings
moderations
files
Adding Hooks
The services come with no hooks by default. You can add hooks by simply setting the hooks property after app.configure
. For example:
export const services = (app) => {
app.configure(openai('openai'))
attachOpenAIhooks(app)
// ... other services
}
function attachOpenAIhooks(app){
app.service('openai/models).hooks({
before:{
all:[()=>console.log('in the models hook!')]
}
})
}
You can also directly leverage the service as part of another service flow, like using the AI to write a title for an article.
app.service('articles').hooks({
before:{ create:[
(ctx)=>{
let text = ctx.data.text;
ctx.data.title = ctx.app.service('openai/completions)
.create({
model: "text-davinci-003",
prompt: `Write a clickbait title for the following text:\n${text}\n####`,
max_tokens: 7,
temperature: 0,
stop:'###'
}).then(r=>r.choices[0].text)
}]
}
})
Known Limitations
Adapter Syntax: feathers-openai
does NOT implement the Feathers Common database adapter API
Pagination: The current OpenAI API does not demonstrate how they will provide pagination for large responses, so for find
method calls, the total
, $limit
and $skip
are server-side manipulations of the OpenAI response and will not reduce the call on the OpenAI side. Any calls to find
will return the standard feathers object { total:x ... data:[...]}
but create
, get
, remove
,update
will return as close to the original OpenAI response.
Queries/Search: There is NO query capability for the OpenAI API so it is not implemented here. This library does not implement the FeathersJS querying syntax.