Public
HTTP (deprecated)
Val Town is a social website to write and deploy JavaScript.
Build APIs and schedule functions from your browser.
Readme

OpenAI Proxy

This OpenAI API proxy injects Val Town's API keys. For usage documentation, check out https://www.val.town/v/std/openai

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import { parseBearerString } from "https://esm.town/v/andreterron/parseBearerString";
import { API_URL } from "https://esm.town/v/std/API_URL?v=5";
import { RateLimit } from "npm:@rlimit/http";
const allowedPathnames = [
"/",
"/v1/chat/completions",
];
const rlimit = new RateLimit({
namespace: Deno.env.get("rlimit_namespace"),
maximum: 10,
interval: "1m",
});
export default async function(req: Request): Promise<Response> {
// Ensure only allowed pathnames are used
const { pathname, search } = new URL(req.url);
if (!allowedPathnames.includes(pathname)) {
return new Response("Path not supported", { status: 404 });
}
// Checks the user identity
const authHeader = req.headers.get("Proxy-Authorization") || req.headers.get("Authorization");
const token = authHeader ? parseBearerString(authHeader) : undefined;
const meRes = await fetch(`${API_URL}/v1/me`, { headers: { Authorization: `Bearer ${token}` } });
if (!meRes.ok) {
return new Response("Unauthorized", { status: 401 });
}
const user = await meRes.json();
// Check rate limit
const { ok } = await rlimit.check(`user:${user.id}`);
if (!ok) {
// Rate limited
return new Response("Too Many Requests", { status: 429 });
}
// Proxy the request
const url = new URL("." + pathname, "https://api.openai.com");
url.search = search;
const headers = new Headers(req.headers);
headers.set("Host", url.hostname);
headers.set("Authorization", `Bearer ${Deno.env.get("OPENAI_API_KEY")}`);
headers.set("OpenAI-Organization", Deno.env.get("OPENAI_API_ORG"));
const openAIRes = await fetch(url, {
method: req.method,
headers,
body: await limitFreeModel(req, user),
redirect: "manual",
});
const res = new Response(openAIRes.body, openAIRes);
// Remove internal header
res.headers.delete("openai-organization");
return res;
}
async function limitFreeModel(req: Request, user: any) {
if (user.tier === "pro") return req.body;
const input = await req.json();
console.log(input);
return JSON.stringify({
...input,
model: "gpt-3.5-turbo",
});
}
// Adapted from https://blog.r0b.io/post/creating-a-proxy-with-deno/
std-limit_model_fork.web.val.run
May 13, 2024