vertex2api / app.js
smgc's picture
Update app.js
b6be6bb verified
raw
history blame
No virus
3.63 kB
const express = require('express');
const fetch = require('node-fetch');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
const MODEL = 'claude-3-5-sonnet@20240620';
const PROJECT_ID = process.env.PROJECT_ID;
const CLIENT_ID = process.env.CLIENT_ID;
const CLIENT_SECRET = process.env.CLIENT_SECRET;
const REFRESH_TOKEN = process.env.REFRESH_TOKEN;
const API_KEY = process.env.API_KEY;
const TOKEN_URL = 'https://www.googleapis.com/oauth2/v4/token';
let tokenCache = {
accessToken: '',
expiry: 0,
refreshPromise: null
};
async function getAccessToken() {
const now = Date.now() / 1000;
if (tokenCache.accessToken && now < tokenCache.expiry - 120) {
return tokenCache.accessToken;
}
if (tokenCache.refreshPromise) {
await tokenCache.refreshPromise;
return tokenCache.accessToken;
}
tokenCache.refreshPromise = (async () => {
try {
const response = await fetch(TOKEN_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
refresh_token: REFRESH_TOKEN,
grant_type: 'refresh_token'
})
});
const data = await response.json();
tokenCache.accessToken = data.access_token;
tokenCache.expiry = now + data.expires_in;
} finally {
tokenCache.refreshPromise = null;
}
})();
await tokenCache.refreshPromise;
return tokenCache.accessToken;
}
function getLocation() {
const currentSeconds = new Date().getSeconds();
return currentSeconds < 30 ? 'europe-west1' : 'us-east5';
}
function constructApiUrl(location) {
return `https://${location}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${location}/publishers/anthropic/models/${MODEL}:streamRawPredict`;
}
async function handleRequest(req, res) {
if (req.method === 'OPTIONS') {
return handleOptions(res);
}
const apiKey = req.headers['x-api-key'];
if (apiKey !== API_KEY) {
return res.status(403).json({
type: "error",
error: {
type: "permission_error",
message: "Your API key does not have permission to use the specified resource."
}
});
}
const accessToken = await getAccessToken();
const location = getLocation();
const apiUrl = constructApiUrl(location);
let requestBody = req.body;
if (requestBody.anthropic_version) {
delete requestBody.anthropic_version;
}
if (requestBody.model) {
delete requestBody.model;
}
requestBody.anthropic_version = "vertex-2023-10-16";
const modifiedHeaders = {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json; charset=utf-8'
};
const response = await fetch(apiUrl, {
headers: modifiedHeaders,
method: 'POST',
body: JSON.stringify(requestBody)
});
const responseBody = await response.text();
res.status(response.status).set(response.headers).send(responseBody);
}
function handleOptions(res) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, x-api-key, anthropic-version, model');
res.sendStatus(204);
}
app.post('/ai/v1/messages', handleRequest);
app.options('/ai/v1/messages', handleOptions);
app.get('/', (req, res) => {
res.status(200).send('Vertex Claude API Proxy');
});
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});