forked from tech-shrimp/gemini-playground
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
195 lines (165 loc) · 5.77 KB
/
index.js
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
const assetManifest = {};
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
// 处理 WebSocket 连接
if (request.headers.get('Upgrade') === 'websocket') {
return handleWebSocket(request, env);
}
// 添加 API 请求处理
if (url.pathname.endsWith("/chat/completions") ||
url.pathname.endsWith("/embeddings") ||
url.pathname.endsWith("/models")) {
return handleAPIRequest(request, env);
}
// 处理静态资源
if (url.pathname === '/' || url.pathname === '/index.html') {
console.log('Serving index.html',env);
return new Response(await env.__STATIC_CONTENT.get('index.html'), {
headers: {
'content-type': 'text/html;charset=UTF-8',
},
});
}
// 处理其他静态资源
const asset = await env.__STATIC_CONTENT.get(url.pathname.slice(1));
if (asset) {
const contentType = getContentType(url.pathname);
return new Response(asset, {
headers: {
'content-type': contentType,
},
});
}
return new Response('Not found', { status: 404 });
},
};
function getContentType(path) {
const ext = path.split('.').pop().toLowerCase();
const types = {
'js': 'application/javascript',
'css': 'text/css',
'html': 'text/html',
'json': 'application/json',
'png': 'image/png',
'jpg': 'image/jpeg',
'jpeg': 'image/jpeg',
'gif': 'image/gif'
};
return types[ext] || 'text/plain';
}
async function handleWebSocket(request, env) {
if (request.headers.get("Upgrade") !== "websocket") {
return new Response("Expected WebSocket connection", { status: 400 });
}
const url = new URL(request.url);
const pathAndQuery = url.pathname + url.search;
const targetUrl = `wss://generativelanguage.googleapis.com${pathAndQuery}`;
console.log('Target URL:', targetUrl);
const [client, proxy] = new WebSocketPair();
proxy.accept();
// 用于存储在连接建立前收到的消息
let pendingMessages = [];
const targetWebSocket = new WebSocket(targetUrl);
console.log('Initial targetWebSocket readyState:', targetWebSocket.readyState);
targetWebSocket.addEventListener("open", () => {
console.log('Connected to target server');
console.log('targetWebSocket readyState after open:', targetWebSocket.readyState);
// 连接建立后,发送所有待处理的消息
console.log(`Processing ${pendingMessages.length} pending messages`);
for (const message of pendingMessages) {
try {
targetWebSocket.send(message);
console.log('Sent pending message:', message);
} catch (error) {
console.error('Error sending pending message:', error);
}
}
pendingMessages = []; // 清空待处理消息队列
});
proxy.addEventListener("message", async (event) => {
console.log('Received message from client:', {
dataPreview: typeof event.data === 'string' ? event.data.slice(0, 200) : 'Binary data',
dataType: typeof event.data,
timestamp: new Date().toISOString()
});
console.log("targetWebSocket.readyState"+targetWebSocket.readyState)
if (targetWebSocket.readyState === WebSocket.OPEN) {
try {
targetWebSocket.send(event.data);
console.log('Successfully sent message to gemini');
} catch (error) {
console.error('Error sending to gemini:', error);
}
} else {
// 如果连接还未建立,将消息加入待处理队列
console.log('Connection not ready, queueing message');
pendingMessages.push(event.data);
}
});
targetWebSocket.addEventListener("message", (event) => {
console.log('Received message from gemini:', {
dataPreview: typeof event.data === 'string' ? event.data.slice(0, 200) : 'Binary data',
dataType: typeof event.data,
timestamp: new Date().toISOString()
});
try {
if (proxy.readyState === WebSocket.OPEN) {
proxy.send(event.data);
console.log('Successfully forwarded message to client');
}
} catch (error) {
console.error('Error forwarding to client:', error);
}
});
targetWebSocket.addEventListener("close", (event) => {
console.log('Gemini connection closed:', {
code: event.code,
reason: event.reason || 'No reason provided',
wasClean: event.wasClean,
timestamp: new Date().toISOString(),
readyState: targetWebSocket.readyState
});
if (proxy.readyState === WebSocket.OPEN) {
proxy.close(event.code, event.reason);
}
});
proxy.addEventListener("close", (event) => {
console.log('Client connection closed:', {
code: event.code,
reason: event.reason || 'No reason provided',
wasClean: event.wasClean,
timestamp: new Date().toISOString()
});
if (targetWebSocket.readyState === WebSocket.OPEN) {
targetWebSocket.close(event.code, event.reason);
}
});
targetWebSocket.addEventListener("error", (error) => {
console.error('Gemini WebSocket error:', {
error: error.message || 'Unknown error',
timestamp: new Date().toISOString(),
readyState: targetWebSocket.readyState
});
});
return new Response(null, {
status: 101,
webSocket: client,
});
}
async function handleAPIRequest(request, env) {
try {
const worker = await import('./api_proxy/worker.mjs');
return await worker.default.fetch(request);
} catch (error) {
console.error('API request error:', error);
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
const errorStatus = error.status || 500;
return new Response(errorMessage, {
status: errorStatus,
headers: {
'content-type': 'text/plain;charset=UTF-8',
}
});
}
}