Skip to content

Commit

Permalink
Prepare for public source code release
Browse files Browse the repository at this point in the history
  • Loading branch information
domdomegg committed May 27, 2024
1 parent 31eebea commit f5de5c3
Show file tree
Hide file tree
Showing 10 changed files with 146 additions and 12 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ jobs:
run: npm run build --if-present
- name: "Test"
run: npm run test --if-present
- name: "Configure for deployment"
if: github.ref == 'refs/heads/master'
run: |
echo "$PROD_ENV" > lib/env.ts
env:
PROD_ENV: ${{ secrets.PROD_ENV }}
- name: "Deploy"
if: github.ref == 'refs/heads/master'
run: npm run deploy
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/node_modules
/.airtableblocksrc.json
/build
.tmp
.tmp
env.ts
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
# ai-evaluator-extension ![deployment automatic](https://img.shields.io/badge/deployment-automatic-success)

Airtable extension for evaluating application to our courses using AI, specifically large language models (LLMS).
[Airtable extension](https://airtable.com/developers/extensions/guides/getting-started) for helping us evaluate applications to our courses using large language models (LLMs).

![Screenshot of the Airtable extension](./screenshot.png)

## Context

We previously manually evaluated each applicant for our educational courses on a set of objective criteria. We would then use these scores plus some additional subjective judgement to come to an application decision. This is time-intensive, and it's difficult to align all the humans to give the same responses for the same person.

In a [previous pilot project](https://github.com/bluedotimpact/ai-application-evaluations-pilot) we concluded that LLMs, while not perfect, could help us automate the first scoring part of our application process.

This repository holds code for an Airtable extension that we can run inside our applications base. We set the relevant inputs (e.g. answers to application questions), the decisioning criteria, and let it evaluate applicants.

## Developer setup

Expand Down
15 changes: 15 additions & 0 deletions lib/env.template.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// For local development, you should usually edit env.ts (and not env.template.ts)
// env.template.ts is a template to set up semi-valid env variables for new projects

// This is very jank
// We're building secrets in to the source code accessible in the browser. This is because Airtable extensions don't have any sensible secret management mechanism.
// We're currently accepting this risk given:
// - only BlueDot Impact employees have access to the deployed extension
// - we have limits on API usage set for both platforms
// - the risk is people using our API credits / getting free access to APIs, which is not as critical (as e.g. applicant's personal data)
export const env = {
// Get from https://platform.openai.com/settings/profile?tab=api-keys
'OPENAI_API_KEY': 'sk-...',
// Get from https://console.anthropic.com/settings/keys
'ANTHROPIC_API_KEY': 'sk-ant-api...'
}
9 changes: 5 additions & 4 deletions lib/getChatCompletion/anthropic/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// This isn't very secure, but given only BlueDot Impact employees should have access to the extension and we have a limit on the usage this is fine for now.
export const anthropicApiKey = "***REMOVED***";
// OpenAI model to use, in the format accepted by the OpenAI API: https://platform.openai.com/docs/models/model-endpoint-compatibility
import { env } from "../../env";

export const anthropicApiKey = env.ANTHROPIC_API_KEY;
// Model to use: https://docs.anthropic.com/en/docs/models-overview
export const anthropicModel = 'claude-3-sonnet-20240229';
// Maximum number of open requests to OpenAI at any one time. Higher = faster, but more likely to hit OpenAI rate limits.
// Maximum number of open requests at any one time. Higher = faster, but more likely to hit rate limits.
export const anthropicRequestConcurrency = 30;
10 changes: 6 additions & 4 deletions lib/getChatCompletion/openai/config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// This isn't very secure, but given only BlueDot Impact employees should have access to the extension and we have a limit on the usage this is fine for now.
export const openAiApiKey = "***REMOVED***";
// OpenAI model to use, in the format accepted by the OpenAI API: https://platform.openai.com/docs/models/model-endpoint-compatibility
import { env } from "../../env";

export const openAiApiKey = env.OPENAI_API_KEY;
export const openAiOrganisation = "org-2egSVUATOaBoS2Slr2CbYrcZ";
// Model to use: https://platform.openai.com/docs/models/model-endpoint-compatibility
export const openAiModel = 'gpt-4-1106-preview';
// Maximum number of open requests to OpenAI at any one time. Higher = faster, but more likely to hit OpenAI rate limits. From trial and error, at tier 3 with GPT-4 turbo, 30 works well.
// Maximum number of open requests at any one time. Higher = faster, but more likely to hit rate limits. From trial and error, at tier 3 with GPT-4 turbo, 30 works well.
export const openAiRequestConcurrency = 30;
4 changes: 2 additions & 2 deletions lib/getChatCompletion/openai/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import pLimit from 'p-limit';
import { openAiRequestConcurrency, openAiApiKey, openAiModel } from './config';
import { openAiRequestConcurrency, openAiApiKey, openAiModel, openAiOrganisation } from './config';
import { GetChatCompletion } from '..';

const globalRateLimit = pLimit(openAiRequestConcurrency);
Expand All @@ -11,7 +11,7 @@ export const getChatCompletion: GetChatCompletion = async (messages) => {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${openAiApiKey}`,
'OpenAI-Organization': 'org-2egSVUATOaBoS2Slr2CbYrcZ',
'OpenAI-Organization': openAiOrganisation,
},
body: JSON.stringify({
model: openAiModel,
Expand Down
94 changes: 94 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
{
"name": "ai-evaluator-extension",
"license": "AGPL-3.0-only",
"private": true,
"scripts": {
"postinstall": "shx cp -n lib/env.template.ts lib/env.ts",
"start": "npm run start:applications",
"start:applications": "block run --remote applications",
"type-check": "tsc --noEmit --esModuleInterop --jsx react frontend/**.tsx lib/**.ts",
Expand All @@ -24,6 +28,7 @@
"eslint-plugin-react": "^7.31.11",
"eslint-plugin-react-hooks": "^4.6.0",
"jest": "^29.3.1",
"shx": "^0.3.4",
"ts-jest": "^29.0.3",
"typescript": "^4.9.4"
},
Expand Down
Binary file added screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit f5de5c3

Please sign in to comment.