gptapi commited on
Commit
1a6955a
·
verified ·
1 Parent(s): 32555cc

Create hf.js

Browse files
Files changed (1) hide show
  1. hf.js +314 -0
hf.js ADDED
@@ -0,0 +1,314 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const express = require('express');
2
+ const morgan = require('morgan');
3
+ const { createProxyMiddleware } = require('http-proxy-middleware');
4
+ const url = require('url');
5
+ const app = express();
6
+
7
+ app.use(morgan('dev'));
8
+
9
+ // 从环境变量获取代理配置
10
+ const proxyUrl = process.env.PROXY || '';
11
+ console.log(`Proxy configuration: ${proxyUrl ? '已配置' : '未配置'}`);
12
+
13
+ // 解析代理URL
14
+ let proxyConfig = null;
15
+ if (proxyUrl) {
16
+ try {
17
+ const parsedUrl = url.parse(proxyUrl);
18
+ proxyConfig = {
19
+ host: parsedUrl.hostname,
20
+ port: parsedUrl.port || 80,
21
+ auth: parsedUrl.auth ? {
22
+ username: parsedUrl.auth.split(':')[0],
23
+ password: parsedUrl.auth.split(':')[1]
24
+ } : undefined
25
+ };
26
+
27
+ // 打印代理配置(安全处理密码)
28
+ const maskedConfig = {
29
+ ...proxyConfig,
30
+ auth: proxyConfig.auth ? {
31
+ username: proxyConfig.auth.username,
32
+ password: '******'
33
+ } : undefined
34
+ };
35
+ console.log('Using proxy:', JSON.stringify(maskedConfig));
36
+ } catch (error) {
37
+ console.error('Failed to parse proxy URL:', error.message);
38
+ }
39
+ }
40
+
41
+ // 添加模型列表API
42
+ app.get('/hf/v1/models', (req, res) => {
43
+ const models = {
44
+ "object": "list",
45
+ "data": [
46
+ {
47
+ "id": "claude-3.5-sonnet",
48
+ "object": "model",
49
+ "created": 1706745938,
50
+ "owned_by": "cursor"
51
+ },
52
+ {
53
+ "id": "gpt-4",
54
+ "object": "model",
55
+ "created": 1706745938,
56
+ "owned_by": "cursor"
57
+ },
58
+ {
59
+ "id": "gpt-4o",
60
+ "object": "model",
61
+ "created": 1706745938,
62
+ "owned_by": "cursor"
63
+ },
64
+ {
65
+ "id": "claude-3-opus",
66
+ "object": "model",
67
+ "created": 1706745938,
68
+ "owned_by": "cursor"
69
+ },
70
+ {
71
+ "id": "gpt-3.5-turbo",
72
+ "object": "model",
73
+ "created": 1706745938,
74
+ "owned_by": "cursor"
75
+ },
76
+ {
77
+ "id": "gpt-4-turbo-2024-04-09",
78
+ "object": "model",
79
+ "created": 1706745938,
80
+ "owned_by": "cursor"
81
+ },
82
+ {
83
+ "id": "gpt-4o-128k",
84
+ "object": "model",
85
+ "created": 1706745938,
86
+ "owned_by": "cursor"
87
+ },
88
+ {
89
+ "id": "gemini-1.5-flash-500k",
90
+ "object": "model",
91
+ "created": 1706745938,
92
+ "owned_by": "cursor"
93
+ },
94
+ {
95
+ "id": "claude-3-haiku-200k",
96
+ "object": "model",
97
+ "created": 1706745938,
98
+ "owned_by": "cursor"
99
+ },
100
+ {
101
+ "id": "claude-3-5-sonnet-200k",
102
+ "object": "model",
103
+ "created": 1706745938,
104
+ "owned_by": "cursor"
105
+ },
106
+ {
107
+ "id": "claude-3-5-sonnet-20241022",
108
+ "object": "model",
109
+ "created": 1706745938,
110
+ "owned_by": "cursor"
111
+ },
112
+ {
113
+ "id": "gpt-4o-mini",
114
+ "object": "model",
115
+ "created": 1706745938,
116
+ "owned_by": "cursor"
117
+ },
118
+ {
119
+ "id": "o1-mini",
120
+ "object": "model",
121
+ "created": 1706745938,
122
+ "owned_by": "cursor"
123
+ },
124
+ {
125
+ "id": "o1-preview",
126
+ "object": "model",
127
+ "created": 1706745938,
128
+ "owned_by": "cursor"
129
+ },
130
+ {
131
+ "id": "o1",
132
+ "object": "model",
133
+ "created": 1706745938,
134
+ "owned_by": "cursor"
135
+ },
136
+ {
137
+ "id": "claude-3.5-haiku",
138
+ "object": "model",
139
+ "created": 1706745938,
140
+ "owned_by": "cursor"
141
+ },
142
+ {
143
+ "id": "gemini-exp-1206",
144
+ "object": "model",
145
+ "created": 1706745938,
146
+ "owned_by": "cursor"
147
+ },
148
+ {
149
+ "id": "gemini-2.0-flash-thinking-exp",
150
+ "object": "model",
151
+ "created": 1706745938,
152
+ "owned_by": "cursor"
153
+ },
154
+ {
155
+ "id": "gemini-2.0-flash-exp",
156
+ "object": "model",
157
+ "created": 1706745938,
158
+ "owned_by": "cursor"
159
+ },
160
+ {
161
+ "id": "deepseek-v3",
162
+ "object": "model",
163
+ "created": 1706745938,
164
+ "owned_by": "cursor"
165
+ },
166
+ {
167
+ "id": "deepseek-r1",
168
+ "object": "model",
169
+ "created": 1706745938,
170
+ "owned_by": "cursor"
171
+ },
172
+ // 新增模型
173
+ {
174
+ "id": "claude-3.7-sonnet",
175
+ "object": "model",
176
+ "created": 1706745938,
177
+ "owned_by": "cursor"
178
+ },
179
+ {
180
+ "id": "claude-3.7-sonnet-thinking",
181
+ "object": "model",
182
+ "created": 1706745938,
183
+ "owned_by": "cursor"
184
+ }
185
+ ]
186
+ };
187
+ res.json(models);
188
+ });
189
+
190
+ // 配置代理中间件
191
+ app.use('/hf/v1/chat/completions', createProxyMiddleware({
192
+ target: 'http://localhost:3010/v1/chat/completions',
193
+ changeOrigin: true,
194
+ // 添加代理配置
195
+ proxy: proxyConfig,
196
+ // 增加错误处理
197
+ onError: (err, req, res) => {
198
+ console.error('Proxy error:', err);
199
+ res.status(500).send('Proxy error occurred: ' + err.message);
200
+ },
201
+ onProxyReq: (proxyReq, req, res) => {
202
+ console.log(`Proxying request to chat completions ${proxyConfig ? 'using proxy' : 'directly'}`);
203
+ },
204
+ onProxyRes: (proxyRes, req, res) => {
205
+ console.log(`Received response with status: ${proxyRes.statusCode}`);
206
+ }
207
+ }));
208
+
209
+ app.get('/', (req, res) => {
210
+ const htmlContent = `
211
+ <!DOCTYPE html>
212
+ <html lang="en">
213
+ <head>
214
+ <meta charset="UTF-8">
215
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
216
+ <title>Cursor To OpenAI</title>
217
+ <style>
218
+ body {
219
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
220
+ max-width: 800px;
221
+ margin: 0 auto;
222
+ padding: 20px;
223
+ line-height: 1.6;
224
+ }
225
+ .container {
226
+ background: #f9f9f9;
227
+ border-radius: 10px;
228
+ padding: 20px;
229
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
230
+ }
231
+ .info-item {
232
+ margin-bottom: 10px;
233
+ }
234
+ .status {
235
+ background: ${proxyConfig ? '#e1f5e1' : '#fff3cd'};
236
+ padding: 10px;
237
+ border-radius: 5px;
238
+ margin-top: 20px;
239
+ border: 1px solid ${proxyConfig ? '#c3e6cb' : '#ffeeba'};
240
+ }
241
+ .models-container {
242
+ margin-top: 20px;
243
+ border-top: 1px solid #eee;
244
+ padding-top: 20px;
245
+ }
246
+ .model-list {
247
+ display: grid;
248
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
249
+ gap: 10px;
250
+ margin-top: 15px;
251
+ }
252
+ .model-item {
253
+ background: #f0f0f0;
254
+ padding: 8px 12px;
255
+ border-radius: 4px;
256
+ font-size: 0.9em;
257
+ }
258
+ </style>
259
+ </head>
260
+ <body>
261
+ <div class="container">
262
+ <h1>Cursor To OpenAI Server</h1>
263
+ <div class="info-item">
264
+ <strong>聊天来源:</strong> 自定义(兼容 OpenAI)
265
+ </div>
266
+ <div class="info-item">
267
+ <strong>自定义端点(基本URL):</strong><span id="endpoint-url"></span>
268
+ </div>
269
+ <div class="info-item">
270
+ <strong>自定义API密钥:</strong>[抓取的Cursor Cookie,格式为user_...]
271
+ </div>
272
+ <div class="status">
273
+ <strong>代理状态:</strong> ${proxyConfig ? '已启用' : '未启用'}
274
+ </div>
275
+
276
+ <div class="models-container">
277
+ <h3>支持的模型</h3>
278
+ <div id="model-list" class="model-list">加载中...</div>
279
+ </div>
280
+ </div>
281
+ <script>
282
+ const url = new URL(window.location.href);
283
+ const link = url.protocol + '//' + url.host + '/hf/v1';
284
+ document.getElementById('endpoint-url').textContent = link;
285
+
286
+ // 加载模型列表
287
+ fetch('/hf/v1/models')
288
+ .then(response => response.json())
289
+ .then(data => {
290
+ const modelListEl = document.getElementById('model-list');
291
+ modelListEl.innerHTML = '';
292
+
293
+ data.data.forEach(model => {
294
+ const modelEl = document.createElement('div');
295
+ modelEl.className = 'model-item';
296
+ modelEl.textContent = model.id;
297
+ modelListEl.appendChild(modelEl);
298
+ });
299
+ })
300
+ .catch(err => {
301
+ document.getElementById('model-list').textContent = '加载模型失败: ' + err.message;
302
+ });
303
+ </script>
304
+ </body>
305
+ </html>
306
+ `;
307
+ res.send(htmlContent);
308
+ });
309
+
310
+ const port = process.env.HF_PORT || 7860;
311
+ app.listen(port, () => {
312
+ console.log(`HF Proxy server is running at PORT: ${port}`);
313
+ console.log(`Proxy status: ${proxyConfig ? 'Enabled' : 'Disabled'}`);
314
+ });