From 3db033418fc7d1b59b27d31352f509ef6390019b Mon Sep 17 00:00:00 2001 From: xiang <1984871009@qq.com> Date: Thu, 29 Jun 2023 11:33:37 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=85=8D=E8=B4=B9=E7=9A=8416k=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- model/base.ts | 1 + model/fakeopen/index.ts | 109 ++++++++++++++++++++++++++++++++++++++++ model/index.ts | 3 ++ 3 files changed, 113 insertions(+) create mode 100644 model/fakeopen/index.ts diff --git a/model/base.ts b/model/base.ts index e6aed81..dfebd9c 100644 --- a/model/base.ts +++ b/model/base.ts @@ -15,6 +15,7 @@ export type Message = { export enum ModelType { GPT3p5Turbo = 'gpt3.5-turbo', + GPT3p5_16k = 'gpt-3.5-turbo-16k', GPT4 = 'gpt4', NetGpt3p5 = 'net-gpt3.5-turbo', } diff --git a/model/fakeopen/index.ts b/model/fakeopen/index.ts new file mode 100644 index 0000000..d0caba2 --- /dev/null +++ b/model/fakeopen/index.ts @@ -0,0 +1,109 @@ +import {Chat, ChatOptions, ChatRequest, ChatResponse, ModelType} from "../base"; +import {AxiosInstance, AxiosRequestConfig, CreateAxiosDefaults} from "axios"; +import {CreateAxiosProxy} from "../../utils/proxyAgent"; +import es from "event-stream"; +import {ErrorData, Event, EventStream, MessageData, parseJSON} from "../../utils"; + +interface Message { + role: string; + content: string; +} + +interface RealReq { + messages: Message[]; + temperature: number; + stream: boolean; + model: string; +} + +export class FakeOpen extends Chat { + private client: AxiosInstance; + + constructor(options?: ChatOptions) { + super(options); + this.client = CreateAxiosProxy({ + baseURL: 'https://ai.fakeopen.com/v1/', + headers: { + 'Content-Type': 'application/json', + "accept": "text/event-stream", + "Cache-Control": "no-cache", + "Proxy-Connection": "keep-alive", + "Authorization": `Bearer ${process.env.FAKE_OPEN_KEY || 'pk-this-is-a-real-free-api-key-pk-for-everyone'}`, + } + } as CreateAxiosDefaults); + } + + support(model: ModelType): number { + switch (model) { + case ModelType.GPT3p5_16k: + return 15000; + default: + return 0; + } + } + + public async ask(req: ChatRequest): Promise { + const stream = new EventStream(); + const res = await this.askStream(req, stream); + const result: ChatResponse = { + content: '', + } + return new Promise(resolve => { + stream.read((event, data) => { + switch (event) { + case Event.done: + break; + case Event.message: + result.content += (data as MessageData).content || ''; + break; + case Event.error: + result.error = (data as ErrorData).error; + break; + } + }, () => { + resolve(result); + }) + }) + + } + + public async askStream(req: ChatRequest, stream: EventStream) { + const data: RealReq = { + messages: [{role: 'user', content: req.prompt}], + temperature: 1.0, + model: req.model, + stream: true + }; + try { + const res = await this.client.post('/chat/completions', data, { + responseType: 'stream', + } as AxiosRequestConfig); + res.data.pipe(es.split(/\r?\n\r?\n/)).pipe(es.map(async (chunk: any, cb: any) => { + const dataStr = chunk.replace('data: ', ''); + if (!dataStr) { + return; + } + if (dataStr === '[DONE]') { + stream.write(Event.done, {content: ''}) + stream.end(); + return; + } + const data = parseJSON(dataStr, {} as any); + if (!data?.choices) { + stream.write(Event.error, {error: 'not found data.choices'}) + stream.end(); + return; + } + const [{delta: {content = ""}, finish_reason}] = data.choices; + if (finish_reason === 'stop') { + return; + } + stream.write(Event.message, {content}); + })) + } catch (e: any) { + console.error(e); + stream.write(Event.error, {error: e.message}) + stream.end(); + } + } +} diff --git a/model/index.ts b/model/index.ts index 7b2c6b4..182e766 100644 --- a/model/index.ts +++ b/model/index.ts @@ -4,6 +4,7 @@ import {Mcbbs} from "./mcbbs"; import {ChatDemo} from "./chatdemo"; import {Phind} from "./phind"; import {Vita} from "./vita"; +import {FakeOpen} from "./fakeopen"; export enum Site { // define new model here @@ -12,6 +13,7 @@ export enum Site { Mcbbs = 'mcbbs', ChatDemo = 'chatdemo', Vita = 'vita', + FakeOpen = 'fakeopen', } export class ChatModelFactory { @@ -31,6 +33,7 @@ export class ChatModelFactory { this.modelMap.set(Site.Mcbbs, new Mcbbs(this.options)) this.modelMap.set(Site.ChatDemo, new ChatDemo(this.options)) this.modelMap.set(Site.Vita, new Vita(this.options)) + this.modelMap.set(Site.FakeOpen, new FakeOpen(this.options)) } get(model: Site): Chat | undefined {