From 935212edd1228fc61469381f757a72961e84cd97 Mon Sep 17 00:00:00 2001 From: weaigc <879821485@qq.com> Date: Fri, 22 Sep 2023 23:04:02 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20openai=20=E6=94=AF=E6=8C=81=E7=BD=91?= =?UTF-8?q?=E9=A1=B5=E7=AB=AF=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 36 ++++++- package.json | 1 + src/pages/api/chat/completions.ts | 108 -------------------- src/pages/api/turing/conversation/create.ts | 2 +- src/pages/middleware.ts | 22 ---- tests/openai.ts | 2 +- 6 files changed, 37 insertions(+), 134 deletions(-) delete mode 100644 src/pages/api/chat/completions.ts delete mode 100644 src/pages/middleware.ts diff --git a/package-lock.json b/package-lock.json index 140e6819..6028eecc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "bingo", - "version": "0.7.0", + "version": "0.8.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "bingo", - "version": "0.7.0", + "version": "0.8.0", "dependencies": { "@headlessui/react": "^1.7.17", "@radix-ui/react-alert-dialog": "^1.0.4", @@ -44,6 +44,7 @@ "next": "13.4.19", "next-auth": "^4.23.1", "next-themes": "^0.2.1", + "nextjs-cors": "^2.1.2", "node-imei": "^1.0.8", "postcss": "8.4.29", "random-ip": "^0.0.1", @@ -5064,6 +5065,18 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/cosmiconfig": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", @@ -9314,6 +9327,17 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/nextjs-cors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/nextjs-cors/-/nextjs-cors-2.1.2.tgz", + "integrity": "sha512-2yOVivaaf2ILe4f/qY32hnj3oC77VCOsUQJQfhVMGsXE/YMEWUY2zy78sH9FKUCM7eG42/l3pDofIzMD781XGA==", + "dependencies": { + "cors": "^2.8.5" + }, + "peerDependencies": { + "next": "^8.1.1-canary.54 || ^9.0.0 || ^10.0.0-0 || ^11.0.0 || ^12.0.0 || ^13.0.0" + } + }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -12026,6 +12050,14 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/vfile": { "version": "5.3.7", "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", diff --git a/package.json b/package.json index d9972a17..cacf3123 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "next": "13.4.19", "next-auth": "^4.23.1", "next-themes": "^0.2.1", + "nextjs-cors": "^2.1.2", "node-imei": "^1.0.8", "postcss": "8.4.29", "random-ip": "^0.0.1", diff --git a/src/pages/api/chat/completions.ts b/src/pages/api/chat/completions.ts deleted file mode 100644 index b651ebd4..00000000 --- a/src/pages/api/chat/completions.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { NextApiRequest, NextApiResponse } from 'next' -import assert from 'assert' -import { BingWebBot } from '@/lib/bots/bing' -import { BingConversationStyle, ConversationInfoBase } from '@/lib/bots/bing/types' - -export const config = { - api: { - responseLimit: false, - }, -} - -export type Role = 'user' | 'assistant' -export type Action = 'next' | 'variant'; - -export interface APIMessage { - role: Role - content: string -} - -export interface APIRequest { - id?: string - model: string - action: Action - messages: APIMessage[] - stream?: boolean -} - -export interface APIResponse { - id?: string - choices: { - delta?: APIMessage - message: APIMessage - }[] -} - -function parseOpenAIMessage(request: APIRequest) { - return { - prompt: request.messages?.reverse().find((message) => message.role === 'user')?.content, - stream: request.stream, - model: request.model, - }; -} - -function responseOpenAIMessage(content: string, id?: string): APIResponse { - const message: APIMessage = { - role: 'assistant', - content, - }; - return { - id, - choices: [{ - delta: message, - message, - }], - }; -} - -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - if (req.method !== 'POST') return res.status(403).end() - const { prompt, stream, model } = parseOpenAIMessage(req.body); - let { id } = req.body - const chatbot = new BingWebBot({ - endpoint: req.headers.origin || `http://127.0.0.1:${process.env.PORT}`, - cookie: `BING_IP=${process.env.BING_IP}` - }) - id ||= JSON.stringify(chatbot.createConversation()) - - if (stream) { - res.setHeader('Content-Type', 'text/event-stream; charset=utf-8') - } - let lastLength = 0 - let lastText = '' - const abortController = new AbortController() - assert(prompt, 'messages can\'t be empty!') - - const toneType = model as BingConversationStyle - chatbot.sendMessage({ - prompt, - options: { - bingConversationStyle: Object.values(BingConversationStyle) - .includes(toneType) ? toneType : BingConversationStyle.Creative, - conversation: JSON.parse(id) as ConversationInfoBase - }, - signal: abortController.signal, - onEvent(event) { - if (event.type === 'UPDATE_ANSWER') { - lastText = event.data.text - if (stream && lastLength !== lastText.length) { - res.write(`data: ${JSON.stringify(responseOpenAIMessage(lastText.slice(lastLength), id))}\n`) - res.flushHeaders() - lastLength = lastText.length - } - } else if (event.type === 'ERROR') { - res.write(`data: ${JSON.stringify(responseOpenAIMessage(`${event.error}`, id))}\n`) - res.flushHeaders() - } else if (event.type === 'DONE') { - if (stream) { - res.end(`data: [DONE]\n`); - } else { - res.json(responseOpenAIMessage(lastText, id)) - } - } - }, - }) - req.socket.once('close', () => { - abortController.abort() - }) -} diff --git a/src/pages/api/turing/conversation/create.ts b/src/pages/api/turing/conversation/create.ts index c90c3583..de1525b0 100644 --- a/src/pages/api/turing/conversation/create.ts +++ b/src/pages/api/turing/conversation/create.ts @@ -1,4 +1,4 @@ -export const runtime = 'experimental-edge' +export const runtime = 'edge' const API_ENDPOINT = 'https://www.bing.com/turing/conversation/create' diff --git a/src/pages/middleware.ts b/src/pages/middleware.ts deleted file mode 100644 index cb84456f..00000000 --- a/src/pages/middleware.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { NextRequest, NextResponse } from 'next/server'; - -export function middleware(request: NextRequest) { - // retrieve the current response - const res = NextResponse.next() - - // add the CORS headers to the response - res.headers.append('Access-Control-Allow-Credentials', 'true') - res.headers.append('Access-Control-Allow-Origin', `https://${request.headers.get('host')}`) - res.headers.append('Access-Control-Allow-Methods', 'GET,DELETE,PATCH,POST,PUT') - res.headers.append( - 'Access-Control-Allow-Headers', - 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version' - ) - - return res -} - -// specify the path regex to apply the middleware to -export const config = { - matcher: '/api/chat/completions', -} diff --git a/tests/openai.ts b/tests/openai.ts index 3159de20..5160f039 100644 --- a/tests/openai.ts +++ b/tests/openai.ts @@ -2,7 +2,7 @@ import OpenAI from 'openai'; const openai = new OpenAI({ apiKey: 'dummy', - baseURL: 'http://127.0.0.1:3000/api' + baseURL: 'https://bing.github1s.tk/api/openai/v1' // 这里改成你自己部署的服务地址 }); async function start() {