Spaces:
Running
Running
Create app.js
Browse files
app.js
ADDED
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// app.js
|
2 |
+
const express = require('express');
|
3 |
+
const fetch = require('node-fetch');
|
4 |
+
const app = express();
|
5 |
+
const port = 8080;
|
6 |
+
|
7 |
+
const MODEL = 'claude-3-5-sonnet@20240620';
|
8 |
+
const PROJECT_ID = process.env.PROJECT_ID;
|
9 |
+
const CLIENT_ID = process.env.CLIENT_ID;
|
10 |
+
const CLIENT_SECRET = process.env.CLIENT_SECRET;
|
11 |
+
const REFRESH_TOKEN = process.env.REFRESH_TOKEN;
|
12 |
+
const API_KEY = process.env.API_KEY;
|
13 |
+
|
14 |
+
const TOKEN_URL = 'https://www.googleapis.com/oauth2/v4/token';
|
15 |
+
|
16 |
+
let tokenCache = {
|
17 |
+
accessToken: '',
|
18 |
+
expiry: 0,
|
19 |
+
refreshPromise: null
|
20 |
+
};
|
21 |
+
|
22 |
+
async function getAccessToken() {
|
23 |
+
const now = Date.now() / 1000;
|
24 |
+
|
25 |
+
if (tokenCache.accessToken && now < tokenCache.expiry - 120) {
|
26 |
+
return tokenCache.accessToken;
|
27 |
+
}
|
28 |
+
|
29 |
+
if (tokenCache.refreshPromise) {
|
30 |
+
await tokenCache.refreshPromise;
|
31 |
+
return tokenCache.accessToken;
|
32 |
+
}
|
33 |
+
|
34 |
+
tokenCache.refreshPromise = (async () => {
|
35 |
+
try {
|
36 |
+
const response = await fetch(TOKEN_URL, {
|
37 |
+
method: 'POST',
|
38 |
+
headers: {
|
39 |
+
'Content-Type': 'application/json'
|
40 |
+
},
|
41 |
+
body: JSON.stringify({
|
42 |
+
client_id: CLIENT_ID,
|
43 |
+
client_secret: CLIENT_SECRET,
|
44 |
+
refresh_token: REFRESH_TOKEN,
|
45 |
+
grant_type: 'refresh_token'
|
46 |
+
})
|
47 |
+
});
|
48 |
+
|
49 |
+
const data = await response.json();
|
50 |
+
|
51 |
+
tokenCache.accessToken = data.access_token;
|
52 |
+
tokenCache.expiry = now + data.expires_in;
|
53 |
+
} finally {
|
54 |
+
tokenCache.refreshPromise = null;
|
55 |
+
}
|
56 |
+
})();
|
57 |
+
|
58 |
+
await tokenCache.refreshPromise;
|
59 |
+
return tokenCache.accessToken;
|
60 |
+
}
|
61 |
+
|
62 |
+
function getLocation() {
|
63 |
+
const currentSeconds = new Date().getSeconds();
|
64 |
+
return currentSeconds < 30 ? 'europe-west1' : 'us-east5';
|
65 |
+
}
|
66 |
+
|
67 |
+
function constructApiUrl(location) {
|
68 |
+
return `https://${location}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${location}/publishers/anthropic/models/${MODEL}:streamRawPredict`;
|
69 |
+
}
|
70 |
+
|
71 |
+
app.use(express.json());
|
72 |
+
|
73 |
+
app.get('/', (req, res) => {
|
74 |
+
res.status(200).send('Vertex Claude API From GCP');
|
75 |
+
});
|
76 |
+
|
77 |
+
app.post('/ai/v1/chat/completions', async (req, res) => {
|
78 |
+
const apiKey = req.headers['x-api-key'];
|
79 |
+
if (apiKey !== API_KEY) {
|
80 |
+
return res.status(403).json({
|
81 |
+
type: "error",
|
82 |
+
error: {
|
83 |
+
type: "permission_error",
|
84 |
+
message: "Your API key does not have permission to use the specified resource."
|
85 |
+
}
|
86 |
+
});
|
87 |
+
}
|
88 |
+
|
89 |
+
const accessToken = await getAccessToken();
|
90 |
+
const location = getLocation();
|
91 |
+
const apiUrl = constructApiUrl(location);
|
92 |
+
|
93 |
+
let requestBody = req.body;
|
94 |
+
|
95 |
+
if (requestBody.anthropic_version) {
|
96 |
+
delete requestBody.anthropic_version;
|
97 |
+
}
|
98 |
+
|
99 |
+
if (requestBody.model === "claude-3-5-sonnet-20240620") {
|
100 |
+
requestBody.model = "claude-3-5-sonnet@20240620";
|
101 |
+
}
|
102 |
+
|
103 |
+
requestBody.anthropic_version = "vertex-2023-10-16";
|
104 |
+
|
105 |
+
try {
|
106 |
+
const response = await fetch(apiUrl, {
|
107 |
+
method: 'POST',
|
108 |
+
headers: {
|
109 |
+
'Authorization': `Bearer ${accessToken}`,
|
110 |
+
'Content-Type': 'application/json; charset=utf-8'
|
111 |
+
},
|
112 |
+
body: JSON.stringify(requestBody)
|
113 |
+
});
|
114 |
+
|
115 |
+
const data = await response.text();
|
116 |
+
res.status(response.status).send(data);
|
117 |
+
} catch (error) {
|
118 |
+
console.error('Error:', error);
|
119 |
+
res.status(500).json({ error: 'Internal Server Error' });
|
120 |
+
}
|
121 |
+
});
|
122 |
+
|
123 |
+
app.listen(port, () => {
|
124 |
+
console.log(`Server running on port ${port}`);
|
125 |
+
});
|