Spaces:
Paused
Paused
| const express = require('express'); | |
| const fetch = require('node-fetch'); | |
| const { v4: uuidv4 } = require('uuid'); | |
| const app = express(); | |
| require('dotenv').config(); | |
| const modelMapping = { | |
| "gpt-4o-mini": "GPT-4o mini", | |
| "claude-haiku": "Claude Haiku", | |
| "llama-3": "Llama 3", | |
| "gemini-1.5": "Gemini 1.5", | |
| "gemini-flash": "Gemini Flash", | |
| "command-r": "Command R" | |
| }; | |
| app.use(express.json()); | |
| const getCurrentTimestamp = () => Math.floor(Date.now() / 1000); | |
| const splitIntoChunks = (text, chunkSize) => { | |
| const chunks = []; | |
| for (let i = 0; i < text.length; i += chunkSize) { | |
| chunks.push(text.slice(i, i + chunkSize)); | |
| } | |
| return chunks; | |
| }; | |
| const getTempUserID = async () => { | |
| try { | |
| const response = await fetch('https://playground.julius.ai/api/temp_user_id'); | |
| const data = await response.json(); | |
| return data.temp_user_id; | |
| } catch (error) { | |
| throw new Error('Failed to get temp user ID'); | |
| } | |
| }; | |
| const sendToJulius = async (tempUserID, message, model) => { | |
| const conversationID = uuidv4(); | |
| const juliusReq = { | |
| message: { | |
| content: message, | |
| role: "user" | |
| }, | |
| provider: "default", | |
| chat_mode: "auto", | |
| client_version: "20240130", | |
| theme: "dark", | |
| selectedModels: [model] | |
| }; | |
| try { | |
| const response = await fetch('https://playground.julius.ai/api/chat/message', { | |
| method: 'POST', | |
| headers: { | |
| 'is-demo': tempUserID, | |
| 'Content-Type': 'application/json', | |
| 'Platform': 'web', | |
| 'conversation-id': conversationID, | |
| 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36' | |
| }, | |
| body: JSON.stringify(juliusReq) | |
| }); | |
| const reader = response.body.pipeThrough(new TextDecoderStream()).getReader(); | |
| let fullResponse = ''; | |
| while (true) { | |
| const { done, value } = await reader.read(); | |
| if (done) break; | |
| const lines = value.split('\n'); | |
| for (const line of lines) { | |
| try { | |
| const jsonResp = JSON.parse(line); | |
| if (jsonResp.content) { | |
| fullResponse += jsonResp.content; | |
| } | |
| } catch (e) { | |
| // 忽略解析错误 | |
| } | |
| } | |
| } | |
| return fullResponse; | |
| } catch (error) { | |
| throw new Error('Failed to send to Julius'); | |
| } | |
| }; | |
| app.all('*', async (req, res) => { | |
| // 身份验证 | |
| const authToken = process.env.AUTH_TOKEN; | |
| if (authToken) { | |
| const requestToken = req.headers.authorization?.replace('Bearer ', ''); | |
| if (!requestToken || requestToken !== authToken) { | |
| return res.status(401).send('Access Denied'); | |
| } | |
| } | |
| // 健康检查 | |
| if (req.path !== '/v1/chat/completions') { | |
| return res.json({ | |
| status: "Julius2Api Service Running...", | |
| message: "MoLoveSze..." | |
| }); | |
| } | |
| if (req.method !== 'POST') { | |
| return res.status(405).send('Method not allowed'); | |
| } | |
| try { | |
| const openAIReq = req.body; | |
| const isStream = openAIReq.stream || false; | |
| // 模型映射 | |
| const mappedModel = modelMapping[openAIReq.model] || 'GPT-4o mini'; | |
| openAIReq.model = mappedModel; | |
| const tempUserID = await getTempUserID(); | |
| const juliusResp = await sendToJulius(tempUserID, | |
| openAIReq.messages[openAIReq.messages.length - 1].content, | |
| mappedModel | |
| ); | |
| const respId = `chatcmpl-${tempUserID}`; | |
| const created = getCurrentTimestamp(); | |
| if (isStream) { | |
| res.writeHead(200, { | |
| 'Content-Type': 'text/event-stream', | |
| 'Cache-Control': 'no-cache', | |
| 'Connection': 'keep-alive' | |
| }); | |
| // 发送初始响应 | |
| const firstResponse = { | |
| id: respId, | |
| object: "chat.completion.chunk", | |
| created: created, | |
| model: mappedModel, | |
| choices: [{ | |
| delta: { role: "assistant" }, | |
| index: 0 | |
| }] | |
| }; | |
| res.write(`data: ${JSON.stringify(firstResponse)}\n\n`); | |
| // 分块发送内容 | |
| const chunks = splitIntoChunks(juliusResp, 50); | |
| chunks.forEach((chunk, index) => { | |
| const response = { | |
| id: respId, | |
| object: "chat.completion.chunk", | |
| created: created, | |
| model: mappedModel, | |
| choices: [{ | |
| delta: { content: chunk }, | |
| index: 0, | |
| finish_reason: index === chunks.length - 1 ? 'stop' : null | |
| }] | |
| }; | |
| res.write(`data: ${JSON.stringify(response)}\n\n`); | |
| }); | |
| res.write('data: [DONE]\n\n'); | |
| res.end(); | |
| } else { | |
| const response = { | |
| id: respId, | |
| object: "chat.completion", | |
| created: created, | |
| model: mappedModel, | |
| choices: [{ | |
| message: { | |
| role: "assistant", | |
| content: juliusResp | |
| }, | |
| finish_reason: "stop" | |
| }] | |
| }; | |
| res.json(response); | |
| } | |
| } catch (error) { | |
| console.error(error); | |
| res.status(500).send(error.message); | |
| } | |
| }); | |
| const PORT = process.env.PORT || 3000; | |
| app.listen(PORT, () => { | |
| console.log(`Server running on port ${PORT}`); | |
| }); |