From 26ad55cb448e59323bef5e488c8642889f5e3a51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A2=AB=E9=81=97=E5=BF=98=E7=9A=84=E8=AE=B0=E5=BF=86?= <32097237+YIWANG-sketch@users.noreply.github.com> Date: Fri, 6 Sep 2024 22:57:46 +0800 Subject: [PATCH] update available models --- index.mjs | 777 +++++++++++++++++++++++++++--------------------------- 1 file changed, 394 insertions(+), 383 deletions(-) diff --git a/index.mjs b/index.mjs index 4393d24..79fe60d 100644 --- a/index.mjs +++ b/index.mjs @@ -1,40 +1,42 @@ import express from "express"; -import { createEvent, getGitRevision } from "./utils.mjs"; +import {createEvent, getGitRevision} from "./utils.mjs"; import YouProvider from "./provider.mjs"; import localtunnel from "localtunnel"; import ngrok from 'ngrok'; -import { v4 as uuidv4 } from "uuid"; +import {v4 as uuidv4} from "uuid"; import './proxyAgent.mjs'; + const app = express(); const port = process.env.PORT || 8080; const validApiKey = process.env.PASSWORD; const availableModels = [ - "gpt_4o", - "gpt_4_turbo", - "gpt_4", - "claude_3_5_sonnet", - "claude_3_opus", - "claude_3_sonnet", - "claude_3_haiku", - "claude_2", - "llama3", - "gemini_pro", - "gemini_1_5_pro", - "databricks_dbrx_instruct", - "command_r", - "command_r_plus", - "zephyr", + "gpt_4o", + "gpt_4_turbo", + "gpt_4", + "claude_3_5_sonnet", + "claude_3_opus", + "claude_3_sonnet", + "claude_3_haiku", + "claude_2", + "llama3", + "gemini_pro", + "gemini_1_5_pro", + "gemini_1_5_flash", + "databricks_dbrx_instruct", + "command_r", + "command_r_plus", + "zephyr", ]; const modelMappping = { - "claude-3-5-sonnet-20240620": "claude_3_5_sonnet", - "claude-3-20240229": "claude_3_opus", - "claude-3-sonnet-20240229": "claude_3_sonnet", - "claude-3-haiku-20240307": "claude_3_haiku", - "claude-2.1": "claude_2", - "claude-2.0": "claude_2", - "gpt-4": "gpt_4", - "gpt-4o": "gpt_4o", - "gpt-4-turbo": "gpt_4_turbo", + "claude-3-5-sonnet-20240620": "claude_3_5_sonnet", + "claude-3-20240229": "claude_3_opus", + "claude-3-sonnet-20240229": "claude_3_sonnet", + "claude-3-haiku-20240307": "claude_3_haiku", + "claude-2.1": "claude_2", + "claude-2.0": "claude_2", + "gpt-4": "gpt_4", + "gpt-4o": "gpt_4o", + "gpt-4-turbo": "gpt_4_turbo", }; // import config.mjs @@ -77,375 +79,384 @@ app.get("/v1/models", OpenAIApiKeyAuth, (req, res) => { name: model, }; }); - res.json({ object: "list", data: models }); + res.json({object: "list", data: models}); }); // handle openai format model request app.post("/v1/chat/completions", OpenAIApiKeyAuth, (req, res) => { - req.rawBody = ""; - req.setEncoding("utf8"); + req.rawBody = ""; + req.setEncoding("utf8"); - req.on("data", function (chunk) { - req.rawBody += chunk; - }); + req.on("data", function (chunk) { + req.rawBody += chunk; + }); - req.on("end", async () => { - console.log("Handling request of OpenAI format"); - res.setHeader("Content-Type", "text/event-stream;charset=utf-8"); - res.setHeader("Access-Control-Allow-Origin", "*"); - let jsonBody = JSON.parse(req.rawBody); + req.on("end", async () => { + console.log("Handling request of OpenAI format"); + res.setHeader("Content-Type", "text/event-stream;charset=utf-8"); + res.setHeader("Access-Control-Allow-Origin", "*"); + let jsonBody = JSON.parse(req.rawBody); - console.log("message length:" + jsonBody.messages.length); - // decide which session to use randomly - let randomSession = Object.keys(provider.sessions)[Math.floor(Math.random() * Object.keys(provider.sessions).length)]; - console.log("Using session " + randomSession); - // call provider to get completion + console.log("message length:" + jsonBody.messages.length); + // decide which session to use randomly + let randomSession = Object.keys(provider.sessions)[Math.floor(Math.random() * Object.keys(provider.sessions).length)]; + console.log("Using session " + randomSession); + // call provider to get completion - // try to map model - if (jsonBody.model && modelMappping[jsonBody.model]) { - jsonBody.model = modelMappping[jsonBody.model]; - } - if (jsonBody.model && !availableModels.includes(jsonBody.model)) { - res.json({ error: { code: 404, message: "Invalid Model" } }); - return; - } - console.log("Using model " + jsonBody.model); + // try to map model + if (jsonBody.model && modelMappping[jsonBody.model]) { + jsonBody.model = modelMappping[jsonBody.model]; + } + if (jsonBody.model && !availableModels.includes(jsonBody.model)) { + res.json({error: {code: 404, message: "Invalid Model"}}); + return; + } + console.log("Using model " + jsonBody.model); - // call provider to get completion - await provider - .getCompletion( - { - username: randomSession, - messages: jsonBody.messages, - stream: !!jsonBody.stream, - proxyModel: jsonBody.model, - useCustomMode: process.env.USE_CUSTOM_MODE === "true" - } - ) - .then(({ completion, cancel }) => { - completion.on("start", (id) => { - if (jsonBody.stream) { - // send message start - res.write(createEvent(":", "queue heartbeat 114514")); - res.write( - createEvent("data", { - id: msgid, - object: "chat.completion.chunk", - created: Math.floor(new Date().getTime() / 1000), - model: jsonBody.model, - system_fingerprint: "114514", - choices: [{ index: 0, delta: { role: "assistant", content: "" }, logprobs: null, finish_reason: null }], - }) - ); - } - }); + // call provider to get completion + await provider + .getCompletion( + { + username: randomSession, + messages: jsonBody.messages, + stream: !!jsonBody.stream, + proxyModel: jsonBody.model, + useCustomMode: process.env.USE_CUSTOM_MODE === "true" + } + ) + .then(({completion, cancel}) => { + completion.on("start", (id) => { + if (jsonBody.stream) { + // send message start + res.write(createEvent(":", "queue heartbeat 114514")); + res.write( + createEvent("data", { + id: msgid, + object: "chat.completion.chunk", + created: Math.floor(new Date().getTime() / 1000), + model: jsonBody.model, + system_fingerprint: "114514", + choices: [{ + index: 0, + delta: {role: "assistant", content: ""}, + logprobs: null, + finish_reason: null + }], + }) + ); + } + }); - completion.on("completion", (id, text) => { - if (jsonBody.stream) { - // send message delta - res.write( - createEvent("data", { - choices: [ - { - content_filter_results: { - hate: { filtered: false, severity: "safe" }, - self_harm: { filtered: false, severity: "safe" }, - sexual: { filtered: false, severity: "safe" }, - violence: { filtered: false, severity: "safe" }, - }, - delta: { content: text }, - finish_reason: null, - index: 0, - }, - ], - created: Math.floor(new Date().getTime() / 1000), - id: id, - model: jsonBody.model, - object: "chat.completion.chunk", - system_fingerprint: "114514", - }) - ); - } else { - // 只会发一次,发送final response - res.write( - JSON.stringify({ - id: id, - object: "chat.completion", - created: Math.floor(new Date().getTime() / 1000), - model: jsonBody.model, - system_fingerprint: "114514", - choices: [ - { - index: 0, - message: { - role: "assistant", - content: text, - }, - logprobs: null, - finish_reason: "stop", - }, - ], - usage: { - prompt_tokens: 1, - completion_tokens: 1, - total_tokens: 1, - }, - }) - ); - res.end(); - } - }); + completion.on("completion", (id, text) => { + if (jsonBody.stream) { + // send message delta + res.write( + createEvent("data", { + choices: [ + { + content_filter_results: { + hate: {filtered: false, severity: "safe"}, + self_harm: {filtered: false, severity: "safe"}, + sexual: {filtered: false, severity: "safe"}, + violence: {filtered: false, severity: "safe"}, + }, + delta: {content: text}, + finish_reason: null, + index: 0, + }, + ], + created: Math.floor(new Date().getTime() / 1000), + id: id, + model: jsonBody.model, + object: "chat.completion.chunk", + system_fingerprint: "114514", + }) + ); + } else { + // 只会发一次,发送final response + res.write( + JSON.stringify({ + id: id, + object: "chat.completion", + created: Math.floor(new Date().getTime() / 1000), + model: jsonBody.model, + system_fingerprint: "114514", + choices: [ + { + index: 0, + message: { + role: "assistant", + content: text, + }, + logprobs: null, + finish_reason: "stop", + }, + ], + usage: { + prompt_tokens: 1, + completion_tokens: 1, + total_tokens: 1, + }, + }) + ); + res.end(); + } + }); - completion.on("end", () => { - if (jsonBody.stream) { - res.write(createEvent("data", "[DONE]")); - res.end(); - } - }); + completion.on("end", () => { + if (jsonBody.stream) { + res.write(createEvent("data", "[DONE]")); + res.end(); + } + }); - res.on("close", () => { - console.log(" > [Client closed]"); - completion.removeAllListeners(); - cancel(); - }); - }) - .catch((error) => { - console.error(error); - if (jsonBody.stream) { - res.write( - createEvent("data", { - choices: [ - { - content_filter_results: { - hate: { filtered: false, severity: "safe" }, - self_harm: { filtered: false, severity: "safe" }, - sexual: { filtered: false, severity: "safe" }, - violence: { filtered: false, severity: "safe" }, - }, - delta: { - content: "Error occurred, please check the log.\n\n出现错误,请检查日志:
" + error.stack || error + "", - }, - finish_reason: null, - index: 0, - }, - ], - created: Math.floor(new Date().getTime() / 1000), - id: uuidv4(), - model: jsonBody.model, - object: "chat.completion.chunk", - system_fingerprint: "114514", - }) - ); - res.end(); - } else { - res.write( - JSON.stringify({ - id: uuidv4(), - object: "chat.completion", - created: Math.floor(new Date().getTime() / 1000), - model: jsonBody.model, - system_fingerprint: "114514", - choices: [ - { - index: 0, - message: { - role: "assistant", - content: "Error occurred, please check the log.\n\n出现错误,请检查日志:
" + error.stack || error + "", - }, - logprobs: null, - finish_reason: "stop", - }, - ], - usage: { - prompt_tokens: 1, - completion_tokens: 1, - total_tokens: 1, - }, - }) - ); - res.end(); - } - }); - }); + res.on("close", () => { + console.log(" > [Client closed]"); + completion.removeAllListeners(); + cancel(); + }); + }) + .catch((error) => { + console.error(error); + if (jsonBody.stream) { + res.write( + createEvent("data", { + choices: [ + { + content_filter_results: { + hate: {filtered: false, severity: "safe"}, + self_harm: {filtered: false, severity: "safe"}, + sexual: {filtered: false, severity: "safe"}, + violence: {filtered: false, severity: "safe"}, + }, + delta: { + content: "Error occurred, please check the log.\n\n出现错误,请检查日志:
" + error.stack || error + "", + }, + finish_reason: null, + index: 0, + }, + ], + created: Math.floor(new Date().getTime() / 1000), + id: uuidv4(), + model: jsonBody.model, + object: "chat.completion.chunk", + system_fingerprint: "114514", + }) + ); + res.end(); + } else { + res.write( + JSON.stringify({ + id: uuidv4(), + object: "chat.completion", + created: Math.floor(new Date().getTime() / 1000), + model: jsonBody.model, + system_fingerprint: "114514", + choices: [ + { + index: 0, + message: { + role: "assistant", + content: "Error occurred, please check the log.\n\n出现错误,请检查日志:
" + error.stack || error + "", + }, + logprobs: null, + finish_reason: "stop", + }, + ], + usage: { + prompt_tokens: 1, + completion_tokens: 1, + total_tokens: 1, + }, + }) + ); + res.end(); + } + }); + }); }); // handle anthropic format model request app.post("/v1/messages", AnthropicApiKeyAuth, (req, res) => { - req.rawBody = ""; - req.setEncoding("utf8"); + req.rawBody = ""; + req.setEncoding("utf8"); - req.on("data", function (chunk) { - req.rawBody += chunk; - }); + req.on("data", function (chunk) { + req.rawBody += chunk; + }); - req.on("end", async () => { - console.log("Handling request of Anthropic format"); - res.setHeader("Content-Type", "text/event-stream;charset=utf-8"); - res.setHeader("Access-Control-Allow-Origin", "*"); - let jsonBody = JSON.parse(req.rawBody); - if (jsonBody.system) { - // 把系统消息加入messages的首条 - jsonBody.messages.unshift({ role: "system", content: jsonBody.system }); - } - console.log("message length:" + jsonBody.messages.length); + req.on("end", async () => { + console.log("Handling request of Anthropic format"); + res.setHeader("Content-Type", "text/event-stream;charset=utf-8"); + res.setHeader("Access-Control-Allow-Origin", "*"); + let jsonBody = JSON.parse(req.rawBody); + if (jsonBody.system) { + // 把系统消息加入messages的首条 + jsonBody.messages.unshift({role: "system", content: jsonBody.system}); + } + console.log("message length:" + jsonBody.messages.length); - // decide which session to use randomly - let randomSession = Object.keys(provider.sessions)[Math.floor(Math.random() * Object.keys(provider.sessions).length)]; - console.log("Using session " + randomSession); + // decide which session to use randomly + let randomSession = Object.keys(provider.sessions)[Math.floor(Math.random() * Object.keys(provider.sessions).length)]; + console.log("Using session " + randomSession); - // decide which model to use - let proxyModel; - if (process.env.AI_MODEL) { - proxyModel = process.env.AI_MODEL; - } else if (jsonBody.model && modelMappping[jsonBody.model]) { - proxyModel = modelMappping[jsonBody.model]; - } else { - proxyModel = "claude_3_opus"; - } - console.log(`Using model ${proxyModel}`); + // decide which model to use + let proxyModel; + if (process.env.AI_MODEL) { + proxyModel = process.env.AI_MODEL; + } else if (jsonBody.model && modelMappping[jsonBody.model]) { + proxyModel = modelMappping[jsonBody.model]; + } else { + proxyModel = "claude_3_opus"; + } + console.log(`Using model ${proxyModel}`); - // call provider to get completion - await provider - .getCompletion({ - username: randomSession, - messages: jsonBody.messages, - stream: !!jsonBody.stream, - proxyModel: proxyModel, - useCustomMode: process.env.USE_CUSTOM_MODE === "true" - }) - .then(({ completion, cancel }) => { - completion.on("start", (id) => { - if (jsonBody.stream) { - // send message start - res.write( - createEvent("message_start", { - type: "message_start", - message: { - id: `${id}`, - type: "message", - role: "assistant", - content: [], - model: proxyModel, - stop_reason: null, - stop_sequence: null, - usage: { input_tokens: 8, output_tokens: 1 }, - }, - }) - ); - res.write(createEvent("content_block_start", { type: "content_block_start", index: 0, content_block: { type: "text", text: "" } })); - res.write(createEvent("ping", { type: "ping" })); - } - }); + // call provider to get completion + await provider + .getCompletion({ + username: randomSession, + messages: jsonBody.messages, + stream: !!jsonBody.stream, + proxyModel: proxyModel, + useCustomMode: process.env.USE_CUSTOM_MODE === "true" + }) + .then(({completion, cancel}) => { + completion.on("start", (id) => { + if (jsonBody.stream) { + // send message start + res.write( + createEvent("message_start", { + type: "message_start", + message: { + id: `${id}`, + type: "message", + role: "assistant", + content: [], + model: proxyModel, + stop_reason: null, + stop_sequence: null, + usage: {input_tokens: 8, output_tokens: 1}, + }, + }) + ); + res.write(createEvent("content_block_start", { + type: "content_block_start", + index: 0, + content_block: {type: "text", text: ""} + })); + res.write(createEvent("ping", {type: "ping"})); + } + }); - completion.on("completion", (id, text) => { - if (jsonBody.stream) { - // send message delta - res.write( - createEvent("content_block_delta", { - type: "content_block_delta", - index: 0, - delta: { type: "text_delta", text: text }, - }) - ); - } else { - // 只会发一次,发送final response - res.write( - JSON.stringify({ - id: id, - content: [ - { - text: text, - }, - { - id: "string", - name: "string", - input: {}, - }, - ], - model: "string", - stop_reason: "end_turn", - stop_sequence: "string", - usage: { - input_tokens: 0, - output_tokens: 0, - }, - }) - ); - res.end(); - } - }); + completion.on("completion", (id, text) => { + if (jsonBody.stream) { + // send message delta + res.write( + createEvent("content_block_delta", { + type: "content_block_delta", + index: 0, + delta: {type: "text_delta", text: text}, + }) + ); + } else { + // 只会发一次,发送final response + res.write( + JSON.stringify({ + id: id, + content: [ + { + text: text, + }, + { + id: "string", + name: "string", + input: {}, + }, + ], + model: "string", + stop_reason: "end_turn", + stop_sequence: "string", + usage: { + input_tokens: 0, + output_tokens: 0, + }, + }) + ); + res.end(); + } + }); - completion.on("end", () => { - if (jsonBody.stream) { - res.write(createEvent("content_block_stop", { type: "content_block_stop", index: 0 })); - res.write( - createEvent("message_delta", { - type: "message_delta", - delta: { stop_reason: "end_turn", stop_sequence: null }, - usage: { output_tokens: 12 }, - }) - ); - res.write(createEvent("message_stop", { type: "message_stop" })); - res.end(); - } - }); + completion.on("end", () => { + if (jsonBody.stream) { + res.write(createEvent("content_block_stop", {type: "content_block_stop", index: 0})); + res.write( + createEvent("message_delta", { + type: "message_delta", + delta: {stop_reason: "end_turn", stop_sequence: null}, + usage: {output_tokens: 12}, + }) + ); + res.write(createEvent("message_stop", {type: "message_stop"})); + res.end(); + } + }); - res.on("close", () => { - console.log(" > [Client closed]"); - completion.removeAllListeners(); - cancel(); - }); - }) - .catch((error) => { - console.error(error); - if (jsonBody.stream) { - res.write( - createEvent("content_block_delta", { - type: "content_block_delta", - index: 0, - delta: { - type: "text_delta", - text: "Error occurred, please check the log.\n\n出现错误,请检查日志:
" + error.stack || error + "", - }, - }) - ); - res.end(); - } else { - res.write( - JSON.stringify({ - id: uuidv4(), - content: [ - { - text: "Error occurred, please check the log.\n\n出现错误,请检查日志:
" + error.stack || error + "", - }, - { - id: "string", - name: "string", - input: {}, - }, - ], - model: "string", - stop_reason: "end_turn", - stop_sequence: "string", - usage: { - input_tokens: 0, - output_tokens: 0, - }, - }) - ); - res.end(); - } - }); - }); + res.on("close", () => { + console.log(" > [Client closed]"); + completion.removeAllListeners(); + cancel(); + }); + }) + .catch((error) => { + console.error(error); + if (jsonBody.stream) { + res.write( + createEvent("content_block_delta", { + type: "content_block_delta", + index: 0, + delta: { + type: "text_delta", + text: "Error occurred, please check the log.\n\n出现错误,请检查日志:
" + error.stack || error + "", + }, + }) + ); + res.end(); + } else { + res.write( + JSON.stringify({ + id: uuidv4(), + content: [ + { + text: "Error occurred, please check the log.\n\n出现错误,请检查日志:
" + error.stack || error + "", + }, + { + id: "string", + name: "string", + input: {}, + }, + ], + model: "string", + stop_reason: "end_turn", + stop_sequence: "string", + usage: { + input_tokens: 0, + output_tokens: 0, + }, + }) + ); + res.end(); + } + }); + }); }); // handle other app.use((req, res, next) => { - const { revision, branch } = getGitRevision(); - res.status(404).send("Not Found (YouChat_Proxy " + revision + "@" + branch + ")"); - console.log("收到了错误路径的请求,请检查您使用的API端点是否正确。") + const {revision, branch} = getGitRevision(); + res.status(404).send("Not Found (YouChat_Proxy " + revision + "@" + branch + ")"); + console.log("收到了错误路径的请求,请检查您使用的API端点是否正确。") }); const createLocaltunnel = async (port, subdomain) => { - const tunnelOptions = { port }; + const tunnelOptions = {port}; if (subdomain) { tunnelOptions.subdomain = subdomain; } @@ -461,7 +472,7 @@ const createLocaltunnel = async (port, subdomain) => { }; const createNgrok = async (port, authToken, customDomain, subdomain) => { - const ngrokOptions = { addr: port, authtoken: authToken }; + const ngrokOptions = {addr: port, authtoken: authToken}; if (customDomain) { ngrokOptions.hostname = customDomain; @@ -514,27 +525,27 @@ app.listen(port, async () => { }); function AnthropicApiKeyAuth(req, res, next) { - const reqApiKey = req.header("x-api-key"); + const reqApiKey = req.header("x-api-key"); - if (validApiKey && reqApiKey !== validApiKey) { - // If Environment variable PASSWORD is set AND x-api-key header is not equal to it, return 401 - const clientIpAddress = req.headers["x-forwarded-for"] || req.ip; - console.log(`Receviced Request from IP ${clientIpAddress} but got invalid password.`); - return res.status(401).json({ error: "Invalid Password" }); - } + if (validApiKey && reqApiKey !== validApiKey) { + // If Environment variable PASSWORD is set AND x-api-key header is not equal to it, return 401 + const clientIpAddress = req.headers["x-forwarded-for"] || req.ip; + console.log(`Receviced Request from IP ${clientIpAddress} but got invalid password.`); + return res.status(401).json({error: "Invalid Password"}); + } - next(); + next(); } function OpenAIApiKeyAuth(req, res, next) { - const reqApiKey = req.header("Authorization"); + const reqApiKey = req.header("Authorization"); - if (validApiKey && reqApiKey !== "Bearer " + validApiKey) { - // If Environment variable PASSWORD is set AND Authorization header is not equal to it, return 401 - const clientIpAddress = req.headers["x-forwarded-for"] || req.ip; - console.log(`Receviced Request from IP ${clientIpAddress} but got invalid password.`); - return res.status(401).json({ error: { code: 403, message: "Invalid Password" } }); - } + if (validApiKey && reqApiKey !== "Bearer " + validApiKey) { + // If Environment variable PASSWORD is set AND Authorization header is not equal to it, return 401 + const clientIpAddress = req.headers["x-forwarded-for"] || req.ip; + console.log(`Receviced Request from IP ${clientIpAddress} but got invalid password.`); + return res.status(401).json({error: {code: 403, message: "Invalid Password"}}); + } - next(); + next(); }