hongshi2025 commited on
Commit
9ed87a2
·
verified ·
1 Parent(s): 2ff0f55

Update main.ts

Browse files
Files changed (1) hide show
  1. main.ts +186 -403
main.ts CHANGED
@@ -1,429 +1,212 @@
1
- import { serve } from "https://deno.land/std@0.220.1/http/server.ts";
2
 
3
- // --- 配置常量 ---
4
- const AUTH_KEY = Deno.env.get("AUTH_KEY") ?? "default_api_key_value"; //API密钥在Environment Variables中添加,否则默认是default_api_key_value
5
- const TARGET_URL = 'https://assistant.on.adaptive.ai/api/sendMessage';
6
- const PROXY_MODEL_NAME = "gpt-4o"; // 代理服务返回的模型名称
7
 
 
 
8
 
9
- const TARGET_HEADERS = {
10
- 'content-type': 'application/json',
11
- 'x-channel-id': "0"
12
- };
13
-
14
- // --- 辅助函数:创建 SSE 数据块 ---
15
- function createSSEChunk(id: string, model: string, content: string | null, role: string | null, finish_reason: string | null): string {
16
- const now = Math.floor(Date.now() / 1000);
17
- const chunk: any = {
18
- id: id,
19
- object: "chat.completion.chunk",
20
- created: now,
21
- model: model,
22
- choices: [
23
- {
24
- index: 0,
25
- delta: {},
26
- finish_reason: finish_reason,
27
- logprobs: null,
28
- }
29
- ],
30
- // system_fingerprint: null, // 可选
31
- };
32
- if (role) {
33
- chunk.choices[0].delta.role = role;
34
- }
35
- if (content) {
36
- chunk.choices[0].delta.content = content;
37
- }
38
- // 如果 delta 为空且有 finish_reason,确保 delta 是空对象
39
- if (!role && !content && finish_reason) {
40
- chunk.choices[0].delta = {};
41
- }
42
-
43
- return `data: ${JSON.stringify(chunk)}\n\n`;
44
  }
45
 
46
- /**
47
- * 向 Adaptive AI 发送创建新聊天的请求。
48
- * 成功时返回新聊天的 ID (字符串)。
49
- * 如果在过程中发生任何错误,则捕获错误并返500。
50
- *
51
- * @returns {Promise<string | 500>} 返回成功创建的聊天的 ID (string),或在失败时返回 500。
52
- */
53
- async function createChatAndGetId(): Promise<string> {
54
- const url = 'https://assistant.on.adaptive.ai/api/createChat';
55
- // 定义请求头 (省略了 cookie 和 priority)
56
- const headers = {
57
- 'content-type': 'application/json',
58
- };
59
- // 构建请求体,使用当前时间戳作为请求 ID
60
- const payload = {
61
- json: {
62
- jsonrpc: "2.0",
63
- id: Date.now(), // 使用动态 ID
64
- method: "createChat",
65
- params: []
66
- }
67
- };
68
- console.log("正在发送创建聊天请求...");
69
- try {
70
- const response = await fetch(url, {
71
- method: 'POST',
72
- headers: headers,
73
- body: JSON.stringify(payload) // 将 payload 对象转换为 JSON 字符串
74
- });
75
- // 检查 HTTP 响应状态码是否表示成功
76
- if (!response.ok) {
77
- let errorBody = "无法读取响应体";
78
- try {
79
- errorBody = await response.text(); // 尝试读取错误响应体
80
- } catch (readError) {
81
- console.warn("读取错误响应体失败:", readError);
82
- }
83
- throw new Error(`创建聊天请求失败,HTTP 状态码: ${response.status}. 响应: ${errorBody}`);
84
- }
85
- // 解析 JSON 响应体
86
- let responseData: any;
87
- try {
88
- responseData = await response.json();
89
- } catch (parseError) {
90
- // 如果响应不是有效的 JSON,则抛出错误
91
- console.error("解析创建聊天响应 JSON 时出错:", parseError);
92
- throw new Error(`无法将响应解析为 JSON: ${parseError.message}`);
93
- }
94
- // 提取并验证 ID
95
- // ID 预期在 responseData.json.result.id
96
- // 使用可选链操作符 (?.) 来安全地访问嵌套属性,防止因中间属性不存在而报错
97
- const chatId = responseData?.json?.result?.id;
98
- // 检查提取到的 ID 是否是一个有效的、非空的字符串
99
- if (typeof chatId === 'string' && chatId.length > 0) {
100
- console.log(`成功创建聊天,获取到 ID: ${chatId}`);
101
- return chatId; // 返回提取到的 ID
102
- } else {
103
- // 如果 ID 不存在或格式不正确,则抛出错误
104
- console.error("从响应中未能提取有效的聊天 ID。响应数据:", JSON.stringify(responseData));
105
- throw new Error("创建聊天的响应格式无效或缺少 'json.result.id' 字段。");
106
- }
107
- } catch (error) {
108
- // 捕获 try 块中抛出的任何错误,或 fetch 本身的网络错误
109
- const errorMessage = error instanceof Error ? error.message : String(error);
110
- console.error("执行 createChatAndGetId 时发生错误:", errorMessage); // 记录详细错误信息
111
- // 创建并返回一个 Response 对象
112
- // 状态码为 500 (Internal Server Error)
113
- // 响应体为 JSON 格式,包含错误信息
114
- return new Response(
115
- JSON.stringify({ error: `创建聊天会话失败: ${errorMessage}` }), // 将错误信息包装在 JSON 对象中
116
- {
117
- status: 500, // 设置 HTTP 状态码为 500
118
- headers: {
119
- "Content-Type": "application/json", // 设置响应内容类型为 JSON
120
- "Access-Control-Allow-Origin": "*" // 如果需要跨域,添加此头
121
- }
122
- }
123
- );
124
- }
125
-
126
  }
127
 
128
- // --- 主处理函数 ---
129
- async function handler(req: Request): Promise<Response> {
130
- const url = new URL(req.url);
 
 
 
 
 
 
 
 
 
 
 
 
 
131
 
132
- // --- CORS 预检请求处理 ---
133
- if (req.method === "OPTIONS") {
134
- return new Response(null, {
135
- status: 204,
136
- headers: {
137
- "Access-Control-Allow-Origin": "*",
138
- "Access-Control-Allow-Methods": "POST, OPTIONS",
139
- "Access-Control-Allow-Headers": "Content-Type, Authorization",
140
- "Access-Control-Max-Age": "86400",
141
- },
142
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  }
144
 
145
-
146
- // 模型列表接口
147
- if (url.pathname === "/v1/models" && req.method === "GET") {
148
- return new Response(
149
- JSON.stringify({
150
- object: "list",
151
- data: [
152
- {
153
- id: "gpt-4o",
154
- object: "model",
155
- created: 0,
156
- owned_by: "unlimitedai",
157
- permission: [{
158
- id: "modelperm-gpt-4o",
159
- object: "model_permission",
160
- created: 0,
161
- allow_create_engine: false,
162
- allow_sampling: true,
163
- allow_logprobs: false,
164
- allow_search_indices: false,
165
- allow_view: true,
166
- allow_fine_tuning: false,
167
- organization: "*",
168
- group: null,
169
- is_blocking: false,
170
- }],
171
- root: "gpt-4o",
172
- parent: null,
173
- },
174
- ],
175
- }),
176
- {
177
- status: 200,
178
- headers: {
179
- "Content-Type": "application/json",
180
- "Access-Control-Allow-Origin": "*",
181
- },
182
- }
183
- );
184
  }
185
 
186
- // --- 路径和方法检查 ---
187
- if (url.pathname !== "/v1/chat/completions" || req.method !== "POST") {
188
- return new Response(JSON.stringify({ error: "Not Found or Method Not Allowed" }), {
189
- status: 404,
190
- headers: {
191
- "Content-Type": "application/json",
192
- "Access-Control-Allow-Origin": "*",
193
- },
194
- });
195
- }
196
- // --- 添加认证检查 ---
197
- const authHeader = req.headers.get("Authorization");
198
- let providedKey = "";
199
- // 检查 Authorization header 是否存在且格式正确 (Bearer <key>)
200
- if (!authHeader || !authHeader.toLowerCase().startsWith("bearer ")) {
201
- console.warn(`认证失败: 缺少或格式错误的 Authorization header`);
202
- return new Response(JSON.stringify({
203
- error: {
204
- message: "Unauthorized: Missing or invalid Authorization header. Use 'Bearer <YOUR_API_KEY>' format.",
205
- type: "invalid_request_error",
206
- param: null,
207
- code: "missing_or_invalid_header"
208
- }
209
- }), {
210
- status: 401, // Unauthorized
211
- headers: {
212
- "Content-Type": "application/json",
213
- "Access-Control-Allow-Origin": "*",
214
- "WWW-Authenticate": 'Bearer realm="API Access"'
215
- }
216
- });
217
- }
218
- // 提取 key 部分
219
- providedKey = authHeader.substring(7); // "Bearer ".length is 7
220
- console.log("providedKey:" + providedKey);
221
- // 直接比较提供的 key 和硬编码的 key
222
- if (providedKey !== AUTH_KEY) {
223
- console.warn(`认证失败: 无效的 API Key 提供`);
224
- return new Response(JSON.stringify({
225
- error: {
226
- message: "Unauthorized: Invalid API Key provided.",
227
- type: "invalid_request_error",
228
- param: null,
229
- code: "inAUTH_KEY"
230
- }
231
- }), {
232
- status: 401, // Unauthorized
233
- headers: {
234
- "Content-Type": "application/json",
235
- "Access-Control-Allow-Origin": "*",
236
- "WWW-Authenticate": 'Bearer realm="API Access"'
237
- }
238
- });
239
- }
240
 
241
- // --- 处理 POST 请求 ---
242
  try {
243
-
244
- // 1. 解析入站请求体
245
- let requestBody: any;
246
- try {
247
- requestBody = await req.json();
248
- console.log(requestBody)
249
- } catch (e) {
250
- console.error("Failed to parse request JSON:", e);
251
- return new Response(JSON.stringify({ error: "Invalid JSON in request body" }), {
252
- status: 400, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" },
253
- });
 
 
 
254
  }
 
 
 
 
 
 
 
 
255
 
256
- // 2. 检查是否请求流式响应
257
- const isStream = requestBody.stream === true;
258
-
259
- // 3. 提取用户输入的内容 - messages 数组转换为字符串
260
- let userContent: string | undefined;
261
- if (Array.isArray(requestBody.messages) && requestBody.messages.length > 0) {
262
- try {
263
- // 直接将整个 messages 数组转换为 JSON 字符串
264
- userContent = JSON.stringify(requestBody.messages);
265
- } catch (e) {
266
- console.error("Failed to stringify 'messages' array:", e);
267
- // 如果 JSON.stringify 失败 (虽然对数组不太可能,但以防万一)
268
- return new Response(JSON.stringify({ error: "Failed to process 'messages' array." }), {
269
- status: 400, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" },
270
- });
271
- }
272
- }
273
- // 检查 userContent 是否成功生成
274
- // 如果 requestBody.messages 不存在、不是数组、为空,或者转换出错,userContent 会是 undefined
275
- if (!userContent) {
276
- console.error("Request body must contain a non-empty 'messages' array.");
277
- return new Response(JSON.stringify({ error: "Request body must contain a non-empty 'messages' array." }), {
278
- status: 400, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" },
279
- });
280
- }
281
-
282
- // 现在 userContent 包含了整个对话历史的字符串表示
283
- console.log("Formatted user content:", userContent); // 可以取消注释来调试输出
284
-
285
- const CHAT_ID = await createChatAndGetId();//获取新的聊天ID
286
-
287
-
288
- // 4. 构建目标 API Payload
289
- const payload = {
290
- json: {
291
- jsonrpc: "2.0", id: Date.now(), method: "sendMessage",
292
- params: [{ chatId: CHAT_ID, content: userContent, fileId: null, fileIds: [] }]
293
- },
294
- meta: { values: { "params.0.fileId": ["undefined"] } }
295
- };
296
 
297
- // 5. 发送请求到目标 API (无论是否流式,都需要先获取完整响应)
298
- console.log("Forwarding request to:", TARGET_URL);
299
- const targetResponse = await fetch(TARGET_URL, {
300
- method: 'POST', headers: TARGET_HEADERS, body: JSON.stringify(payload),
301
- });
 
 
 
 
 
302
 
303
- // 6. 处理目标 API 的响应
304
- if (!targetResponse.ok) {
305
- const errorBody = await targetResponse.text();
306
- console.error(`Target API Error (${targetResponse.status}):`, errorBody);
307
- // 即使是流式请求失败,也返回 JSON 错误
308
- return new Response(JSON.stringify({ error: `Upstream API request failed with status ${targetResponse.status}`, details: errorBody }), {
309
- status: 502, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" },
310
- });
311
- }
312
 
313
- // 7. 解析目标 API 的 JSON 响应
314
- let targetData: any;
315
  try {
316
- targetData = await targetResponse.json();
317
- } catch (e) {
318
- console.error("Failed to parse target API response JSON:", e);
319
- // 即使是流式请求失败,也返回 JSON 错误
320
- return new Response(JSON.stringify({ error: "Failed to parse upstream API response" }), {
321
- status: 500, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" },
322
- });
323
- }
324
-
325
- // 8. 从目标响应中提取内容
326
- const assistantContent = targetData?.json?.result?.content;
327
- if (typeof assistantContent !== 'string') {
328
- console.error("Could not extract 'content' from target API response:", JSON.stringify(targetData));
329
- // 即使是流式请求失败,也返回 JSON 错误
330
- return new Response(JSON.stringify({ error: "Invalid response format from upstream API" }), {
331
- status: 500, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" },
332
- });
333
- }
334
-
335
- // 9. 根据 isStream 决定返回格式
336
- const chatCompletionId = `chatcmpl-${crypto.randomUUID()}`; // 为本次交互生成唯一 ID
337
- const modelName = requestBody.model || PROXY_MODEL_NAME; // 确定模型名称
338
-
339
- if (isStream) {
340
- // --- 返回模拟的流式响应 ---
341
- console.log("Simulating stream response...");
342
- const encoder = new TextEncoder();
343
- const stream = new ReadableStream({
344
- async start(controller) {
345
- try {
346
- // 模拟发送块
347
- // 块 1: 发送角色信息
348
- controller.enqueue(encoder.encode(
349
- createSSEChunk(chatCompletionId, modelName, null, "assistant", null)
350
- ));
351
- await new Promise(resolve => setTimeout(resolve, 10)); // 短暂延迟,模拟处理
352
-
353
- // 块 2: 发送完整内容
354
- controller.enqueue(encoder.encode(
355
- createSSEChunk(chatCompletionId, modelName, assistantContent, null, null)
356
- ));
357
- await new Promise(resolve => setTimeout(resolve, 10)); // 短暂延迟
358
-
359
- // 块 3: 发送结束信号
360
- controller.enqueue(encoder.encode(
361
- createSSEChunk(chatCompletionId, modelName, null, null, "stop")
362
- ));
363
-
364
- // 发送 [DONE] 标记
365
- controller.enqueue(encoder.encode("data: [DONE]\n\n"));
366
-
367
- // 关闭流
368
- controller.close();
369
- } catch (error) {
370
- console.error("Error during stream simulation:", error);
371
- controller.error(error); // 通知流出错了
372
- }
373
- }
374
- });
375
-
376
- return new Response(stream, {
377
- status: 200,
378
- headers: {
379
- 'Content-Type': 'text/event-stream',
380
- 'Cache-Control': 'no-cache',
381
- 'Connection': 'keep-alive', // 建议 SSE 使用
382
- 'Access-Control-Allow-Origin': '*'
383
- },
384
- });
385
-
386
- } else {
387
- // --- 返回完整的 JSON 响应 ---
388
- console.log("Returning non-stream response.");
389
- const finalResponse = {
390
- id: chatCompletionId,
391
- object: "chat.completion",
392
- created: Math.floor(Date.now() / 1000),
393
- model: modelName,
394
- choices: [
395
- {
396
- index: 0,
397
- message: {
398
- role: "assistant",
399
- content: assistantContent,
400
- },
401
- finish_reason: "stop",
402
- logprobs: null,
403
- }
404
- ],
405
- usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },
406
- };
407
-
408
- return new Response(JSON.stringify(finalResponse), {
409
- status: 200,
410
- headers: {
411
- 'Content-Type': 'application/json',
412
- 'Access-Control-Allow-Origin': '*'
413
- },
414
- });
415
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
416
 
417
- } catch (error) {
418
- // --- 全局错误处理 ---
419
- console.error("Unhandled error in handler:", error);
420
- // 即使请求流式,也返回 JSON 错误
421
- return new Response(JSON.stringify({ error: "Internal Server Error" }), {
422
- status: 500,
423
- headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" },
424
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
425
  }
 
 
 
 
426
  }
427
 
 
 
 
 
 
 
428
 
429
- serve(handler, { port: 7860 });
 
1
+ // main.ts - Deno 版本的 ish2api 服务 (v1.0.2 - With Sponsor Adblock)
2
 
3
+ import { serve } from "https://deno.land/[email protected]/http/server.ts";
4
+ import { load } from "https://deno.land/[email protected]/dotenv/mod.ts";
 
 
5
 
6
+ // 加载环境变量
7
+ const env = await load();
8
 
9
+ // --- 类型定义 ---
10
+ interface ChatMessage {
11
+ role: string;
12
+ content: string;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  }
14
 
15
+ interface OpenAIChatRequest {
16
+ model: string;
17
+ messages: ChatMessage[];
18
+ max_tokens?: number;
19
+ temperature?: number;
20
+ stream?: boolean;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  }
22
 
23
+ // --- 配置 ---
24
+ const POLLINATIONS_HEADERS = {
25
+ 'Accept': '*/*',
26
+ 'Accept-Encoding': 'gzip, deflate, br, zstd',
27
+ 'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
28
+ 'Content-Type': 'application/json',
29
+ 'Origin': 'https://ish.junioralive.in',
30
+ 'Referer': 'https://ish.junioralive.in/',
31
+ 'Sec-Ch-Ua': '"Not/A)Brand";v="8", "Chromium";v="126", "Microsoft Edge";v="126"',
32
+ 'Sec-Ch-Ua-Mobile': '?0',
33
+ 'Sec-Ch-Ua-Platform': '"Windows"',
34
+ 'Sec-Fetch-Dest': 'empty',
35
+ 'Sec-Fetch-Mode': 'cors',
36
+ 'Sec-Fetch-Site': 'cross-site',
37
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0',
38
+ };
39
 
40
+ const TARGET_URL = env.TARGET_URL || Deno.env.get("TARGET_URL") || "https://text.pollinations.ai/openai";
41
+
42
+ // --- 核心:流式代理函数 ---
43
+ async function* streamProxy(requestBody: OpenAIChatRequest): AsyncGenerator<Uint8Array> {
44
+ try {
45
+ const response = await fetch(TARGET_URL, {
46
+ method: "POST",
47
+ headers: POLLINATIONS_HEADERS,
48
+ body: JSON.stringify(requestBody),
49
+ });
50
+
51
+ if (!response.ok) {
52
+ const errorText = await response.text();
53
+ const errorDetails = {
54
+ error: {
55
+ message: `Upstream API error: ${response.status}`,
56
+ type: "upstream_error",
57
+ details: errorText
58
+ }
59
+ };
60
+ const errorMessage = `data: ${JSON.stringify(errorDetails)}\n\n`;
61
+ yield new TextEncoder().encode(errorMessage);
62
+ console.error(`Error from upstream API: ${response.status} - ${errorText}`);
63
+ return;
64
  }
65
 
66
+ if (!response.body) {
67
+ throw new Error("Response body is null");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  }
69
 
70
+ const reader = response.body.getReader();
71
+ const textDecoder = new TextDecoder();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
 
 
73
  try {
74
+ while (true) {
75
+ const { done, value } = await reader.read();
76
+
77
+ if (done) break;
78
+
79
+ // =================== 广告过滤逻辑开始 ===================
80
+ // 将二进制块解码为字符串以便检查内容
81
+ const chunkStr = textDecoder.decode(value, { stream: true });
82
+
83
+ // 检查解码后的字符串是否包含 "Sponsor" 关键词
84
+ if (chunkStr.includes("Sponsor")) {
85
+ console.log("Sponsor content detected. Stopping the stream to the client.");
86
+ // 发现广告,立即中断循环,不再向客户端发送任何数据
87
+ break;
88
  }
89
+
90
+ // 如果没有广告,将原始的二进制块转发给客户端
91
+ yield value;
92
+ // =================== 广告过滤逻辑结束 ===================
93
+ }
94
+ } finally {
95
+ reader.releaseLock();
96
+ }
97
 
98
+ } catch (error) {
99
+ const errorDetails = {
100
+ error: {
101
+ message: `An unexpected error occurred: ${error.message}`,
102
+ type: "proxy_error"
103
+ }
104
+ };
105
+ const errorMessage = `data: ${JSON.stringify(errorDetails)}\n\n`;
106
+ yield new TextEncoder().encode(errorMessage);
107
+ console.error(`An unexpected error occurred: ${error}`);
108
+ }
109
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
 
111
+ // --- 路由处理 ---
112
+ async function handleChatCompletions(request: Request): Promise<Response> {
113
+ try {
114
+ const payload = await request.json() as OpenAIChatRequest;
115
+
116
+ // 强制启用流式传输
117
+ const requestBody = {
118
+ ...payload,
119
+ stream: true
120
+ };
121
 
122
+ console.log(`Forwarding request for model '${payload.model}' to ${TARGET_URL}`);
 
 
 
 
 
 
 
 
123
 
124
+ const stream = new ReadableStream({
125
+ async start(controller) {
126
  try {
127
+ for await (const chunk of streamProxy(requestBody)) {
128
+ controller.enqueue(chunk);
129
+ }
130
+ controller.close();
131
+ } catch (error) {
132
+ controller.error(error);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  }
134
+ }
135
+ });
136
+
137
+ return new Response(stream, {
138
+ headers: {
139
+ 'Content-Type': 'text/event-stream',
140
+ 'Cache-Control': 'no-cache',
141
+ 'Connection': 'keep-alive',
142
+ 'Access-Control-Allow-Origin': '*',
143
+ 'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
144
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
145
+ },
146
+ });
147
+
148
+ } catch (error) {
149
+ console.error('Error parsing request:', error);
150
+ return new Response(JSON.stringify({
151
+ error: {
152
+ message: 'Invalid request format',
153
+ type: 'request_error'
154
+ }
155
+ }), {
156
+ status: 400,
157
+ headers: { 'Content-Type': 'application/json' }
158
+ });
159
+ }
160
+ }
161
 
162
+ // --- 主处理函数 ---
163
+ async function handler(request: Request): Promise<Response> {
164
+ const url = new URL(request.url);
165
+ const { pathname, method } = { pathname: url.pathname, method: request.method };
166
+
167
+ // 处理 CORS 预检请求
168
+ if (method === 'OPTIONS') {
169
+ return new Response(null, {
170
+ headers: {
171
+ 'Access-Control-Allow-Origin': '*',
172
+ 'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
173
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
174
+ },
175
+ });
176
+ }
177
+
178
+ // 路由分发
179
+ if (pathname === '/v1/chat/completions' && method === 'POST') {
180
+ return handleChatCompletions(request);
181
+ }
182
+
183
+ if (pathname === '/' && method === 'GET') {
184
+ return new Response(JSON.stringify({
185
+ message: "Pollinations OpenAI-Compatible Proxy is running. Use the /v1/chat/completions endpoint.",
186
+ version: "1.0.2",
187
+ target_url: TARGET_URL
188
+ }), {
189
+ headers: { 'Content-Type': 'application/json' }
190
+ });
191
+ }
192
+
193
+ // 404 处理
194
+ return new Response(JSON.stringify({
195
+ error: {
196
+ message: 'Not Found',
197
+ type: 'not_found'
198
  }
199
+ }), {
200
+ status: 404,
201
+ headers: { 'Content-Type': 'application/json' }
202
+ });
203
  }
204
 
205
+ // --- 启动服务器 ---
206
+ const port = parseInt(Deno.env.get("PORT") || "7860");
207
+
208
+ console.log("Starting Deno server...");
209
+ console.log(`Forwarding requests to: ${TARGET_URL}`);
210
+ console.log(`OpenAI compatible endpoint available at: http://127.0.0.1:${port}/v1/chat/completions`);
211
 
212
+ await serve(handler, { port });