Spaces:
Running
Running
Update app.js
Browse files
app.js
CHANGED
@@ -1,7 +1,10 @@
|
|
1 |
const express = require('express');
|
2 |
const fetch = require('node-fetch');
|
|
|
|
|
|
|
3 |
|
4 |
-
const
|
5 |
|
6 |
const PROJECT_ID = process.env.PROJECT_ID;
|
7 |
const CLIENT_ID = process.env.CLIENT_ID;
|
@@ -17,7 +20,6 @@ let tokenCache = {
|
|
17 |
refreshPromise: null
|
18 |
};
|
19 |
|
20 |
-
// 日志函数
|
21 |
function logRequest(req, status, message) {
|
22 |
const timestamp = new Date().toISOString();
|
23 |
const method = req.method;
|
@@ -71,8 +73,15 @@ function getLocation() {
|
|
71 |
return currentSeconds < 30 ? 'europe-west1' : 'us-east5';
|
72 |
}
|
73 |
|
74 |
-
function constructApiUrl(location) {
|
75 |
-
return `https://${location}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${location}/publishers/anthropic/models/${
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
}
|
77 |
|
78 |
async function handleRequest(req, res) {
|
@@ -97,10 +106,14 @@ async function handleRequest(req, res) {
|
|
97 |
|
98 |
const accessToken = await getAccessToken();
|
99 |
const location = getLocation();
|
100 |
-
const apiUrl = constructApiUrl(location);
|
101 |
|
102 |
let requestBody = req.body;
|
103 |
|
|
|
|
|
|
|
|
|
|
|
104 |
if (requestBody.anthropic_version) {
|
105 |
delete requestBody.anthropic_version;
|
106 |
}
|
@@ -116,21 +129,39 @@ async function handleRequest(req, res) {
|
|
116 |
method: 'POST',
|
117 |
headers: {
|
118 |
'Authorization': `Bearer ${accessToken}`,
|
119 |
-
'Content-Type': 'application/json; charset=utf-8'
|
|
|
120 |
},
|
121 |
body: JSON.stringify(requestBody)
|
122 |
});
|
123 |
|
124 |
res.status(response.status);
|
125 |
-
|
126 |
-
|
127 |
-
|
|
|
|
|
|
|
|
|
128 |
res.setHeader('Access-Control-Allow-Origin', '*');
|
129 |
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
|
130 |
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, x-api-key, anthropic-version, model');
|
131 |
|
132 |
-
|
133 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
134 |
} catch (error) {
|
135 |
console.error('Error:', error);
|
136 |
res.status(500).json({
|
|
|
1 |
const express = require('express');
|
2 |
const fetch = require('node-fetch');
|
3 |
+
const zlib = require('zlib');
|
4 |
+
const stream = require('stream');
|
5 |
+
const { promisify } = require('util');
|
6 |
|
7 |
+
const pipeline = promisify(stream.pipeline);
|
8 |
|
9 |
const PROJECT_ID = process.env.PROJECT_ID;
|
10 |
const CLIENT_ID = process.env.CLIENT_ID;
|
|
|
20 |
refreshPromise: null
|
21 |
};
|
22 |
|
|
|
23 |
function logRequest(req, status, message) {
|
24 |
const timestamp = new Date().toISOString();
|
25 |
const method = req.method;
|
|
|
73 |
return currentSeconds < 30 ? 'europe-west1' : 'us-east5';
|
74 |
}
|
75 |
|
76 |
+
function constructApiUrl(location, model) {
|
77 |
+
return `https://${location}-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/${location}/publishers/anthropic/models/${model}:streamRawPredict`;
|
78 |
+
}
|
79 |
+
|
80 |
+
function formatModelName(model) {
|
81 |
+
if (model === 'claude-3-5-sonnet-20240620') {
|
82 |
+
return 'claude-3-5-sonnet@20240620';
|
83 |
+
}
|
84 |
+
return model;
|
85 |
}
|
86 |
|
87 |
async function handleRequest(req, res) {
|
|
|
106 |
|
107 |
const accessToken = await getAccessToken();
|
108 |
const location = getLocation();
|
|
|
109 |
|
110 |
let requestBody = req.body;
|
111 |
|
112 |
+
let model = requestBody.model || 'claude-3-5-sonnet@20240620';
|
113 |
+
model = formatModelName(model);
|
114 |
+
|
115 |
+
const apiUrl = constructApiUrl(location, model);
|
116 |
+
|
117 |
if (requestBody.anthropic_version) {
|
118 |
delete requestBody.anthropic_version;
|
119 |
}
|
|
|
129 |
method: 'POST',
|
130 |
headers: {
|
131 |
'Authorization': `Bearer ${accessToken}`,
|
132 |
+
'Content-Type': 'application/json; charset=utf-8',
|
133 |
+
'Accept-Encoding': 'gzip, deflate'
|
134 |
},
|
135 |
body: JSON.stringify(requestBody)
|
136 |
});
|
137 |
|
138 |
res.status(response.status);
|
139 |
+
|
140 |
+
for (const [key, value] of response.headers.entries()) {
|
141 |
+
if (key.toLowerCase() !== 'content-encoding' && key.toLowerCase() !== 'content-length') {
|
142 |
+
res.setHeader(key, value);
|
143 |
+
}
|
144 |
+
}
|
145 |
+
|
146 |
res.setHeader('Access-Control-Allow-Origin', '*');
|
147 |
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
|
148 |
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization, x-api-key, anthropic-version, model');
|
149 |
|
150 |
+
const contentEncoding = response.headers.get('content-encoding');
|
151 |
+
if (contentEncoding === 'gzip') {
|
152 |
+
await pipeline(
|
153 |
+
response.body,
|
154 |
+
zlib.createGunzip(),
|
155 |
+
res
|
156 |
+
);
|
157 |
+
} else {
|
158 |
+
await pipeline(
|
159 |
+
response.body,
|
160 |
+
res
|
161 |
+
);
|
162 |
+
}
|
163 |
+
|
164 |
+
logRequest(req, response.status, `Request forwarded successfully for model: ${model}`);
|
165 |
} catch (error) {
|
166 |
console.error('Error:', error);
|
167 |
res.status(500).json({
|