|
import http from 'http'; |
|
import { sendChat, sendChatStream } from './chatwrapper'; |
|
import { mapRequest, mapResponse, mapStreamChunk } from './mapper'; |
|
|
|
|
|
const PORT = Number(process.env.PORT ?? 11434); |
|
|
|
|
|
function allowCors(res: http.ServerResponse) { |
|
res.setHeader('Access-Control-Allow-Origin', '*'); |
|
res.setHeader('Access-Control-Allow-Headers', '*'); |
|
res.setHeader('Access-Control-Allow-Methods', 'GET,POST,OPTIONS'); |
|
} |
|
|
|
|
|
function readJSON( |
|
req: http.IncomingMessage, |
|
res: http.ServerResponse, |
|
): Promise<any | null> { |
|
return new Promise((resolve) => { |
|
let data = ''; |
|
req.on('data', (c) => (data += c)); |
|
req.on('end', () => { |
|
try { |
|
resolve(data ? JSON.parse(data) : {}); |
|
} catch { |
|
res.writeHead(400).end(); |
|
resolve(null); |
|
} |
|
}); |
|
}); |
|
} |
|
|
|
|
|
http |
|
.createServer(async (req, res) => { |
|
allowCors(res); |
|
|
|
|
|
if (req.method === 'OPTIONS') { |
|
res.writeHead(204).end(); |
|
return; |
|
} |
|
|
|
|
|
if (req.url === '/v1/models') { |
|
res.writeHead(200, { 'Content-Type': 'application/json' }); |
|
res.end( |
|
JSON.stringify({ |
|
data: [ |
|
{ |
|
id: 'gemini-2.5-pro-latest', |
|
object: 'model', |
|
owned_by: 'google', |
|
}, |
|
], |
|
}), |
|
); |
|
return; |
|
} |
|
|
|
|
|
if (req.url === '/v1/chat/completions' && req.method === 'POST') { |
|
const body = await readJSON(req, res); |
|
if (!body) return; |
|
|
|
try { |
|
const { geminiReq, tools } = await mapRequest(body); |
|
|
|
if (body.stream) { |
|
res.writeHead(200, { |
|
'Content-Type': 'text/event-stream', |
|
'Cache-Control': 'no-cache', |
|
Connection: 'keep-alive', |
|
}); |
|
|
|
for await (const chunk of sendChatStream({ ...geminiReq, tools })) { |
|
res.write(`data: ${JSON.stringify(mapStreamChunk(chunk))}\n\n`); |
|
} |
|
res.end('data: [DONE]\n\n'); |
|
} else { |
|
const gResp = await sendChat({ ...geminiReq, tools }); |
|
res.writeHead(200, { 'Content-Type': 'application/json' }); |
|
res.end(JSON.stringify(mapResponse(gResp))); |
|
} |
|
} catch (err: any) { |
|
console.error('Proxy error β', err); |
|
res.writeHead(500, { 'Content-Type': 'application/json' }); |
|
res.end(JSON.stringify({ error: { message: err.message } })); |
|
} |
|
return; |
|
} |
|
|
|
|
|
res.writeHead(404).end(); |
|
}) |
|
.listen(PORT, () => console.log(`OpenAI proxy on :${PORT}`)); |
|
|