feat: keep forefront alive always
このコミットが含まれているのは:
コミット
67008b75a2
23
index.ts
23
index.ts
|
@ -1,10 +1,21 @@
|
|||
import Koa from 'koa';
|
||||
import Koa, {Context, Next} from 'koa';
|
||||
import Router from 'koa-router'
|
||||
import bodyParser from 'koa-bodyparser';
|
||||
import {ChatModelFactory, Model} from "./model";
|
||||
|
||||
const app = new Koa();
|
||||
const router = new Router();
|
||||
const errorHandler = async (ctx: Context, next: Next) => {
|
||||
try {
|
||||
await next();
|
||||
} catch (err:any) {
|
||||
ctx.response.status = err.status || 500;
|
||||
ctx.response.body = {
|
||||
message: err.message,
|
||||
};
|
||||
}
|
||||
};
|
||||
app.use(errorHandler);
|
||||
app.use(bodyParser());
|
||||
const chatModel = new ChatModelFactory({proxy: process.env.https_proxy || process.env.http_proxy});
|
||||
|
||||
|
@ -14,7 +25,7 @@ interface AskReq {
|
|||
}
|
||||
|
||||
router.get('/ask', async (ctx) => {
|
||||
const {prompt, model = Model.Forefront} = ctx.query as unknown as AskReq;
|
||||
const {prompt, model = Model.Forefront, ...options} = ctx.query as unknown as AskReq;
|
||||
if (!prompt) {
|
||||
ctx.body = 'please input prompt';
|
||||
return;
|
||||
|
@ -24,12 +35,12 @@ router.get('/ask', async (ctx) => {
|
|||
ctx.body = 'Unsupported model';
|
||||
return;
|
||||
}
|
||||
const res = await chat.ask({prompt: prompt as string});
|
||||
const res = await chat.ask({prompt: prompt as string, options});
|
||||
ctx.body = res.text;
|
||||
});
|
||||
|
||||
router.get('/ask/stream', async (ctx) => {
|
||||
const {prompt, model = Model.Forefront} = ctx.query as unknown as AskReq;
|
||||
const {prompt, model = Model.Forefront, ...options} = ctx.query as unknown as AskReq;
|
||||
if (!prompt) {
|
||||
ctx.body = 'please input prompt';
|
||||
return;
|
||||
|
@ -44,12 +55,12 @@ router.get('/ask/stream', async (ctx) => {
|
|||
"Cache-Control": "no-cache",
|
||||
"Connection": "keep-alive",
|
||||
});
|
||||
const res = await chat.askStream({prompt: prompt as string});
|
||||
const res = await chat.askStream({prompt: prompt as string, options});
|
||||
ctx.body = res.text;
|
||||
})
|
||||
|
||||
app.use(router.routes());
|
||||
|
||||
app.listen(3000,()=>{
|
||||
app.listen(3000, () => {
|
||||
console.log("Now listening: 127.0.0.1:3000");
|
||||
});
|
||||
|
|
|
@ -16,21 +16,14 @@ export interface ResponseStream {
|
|||
|
||||
export interface Request {
|
||||
prompt: string;
|
||||
history?: HistoryItem[];
|
||||
options?: any;
|
||||
}
|
||||
|
||||
export interface HistoryItem {
|
||||
question?: string;
|
||||
answer?: string;
|
||||
}
|
||||
|
||||
|
||||
export abstract class Chat {
|
||||
protected proxy: string | undefined;
|
||||
protected options: ChatOptions | undefined;
|
||||
|
||||
protected constructor(options?: ChatOptions) {
|
||||
this.proxy = options?.proxy;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public abstract ask(req: Request): Promise<Response>
|
||||
|
|
|
@ -13,9 +13,11 @@ interface ForefrontRequest extends Request {
|
|||
options?: {
|
||||
chatId?: string;
|
||||
prompt?: string;
|
||||
actionType?: string;
|
||||
actionType?: Action;
|
||||
defaultPersona?: string;
|
||||
model?: string;
|
||||
gptmodel?: Model;
|
||||
// if set true, auto sign up when gpt4 times use up
|
||||
resignup?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,9 +50,15 @@ export enum Action {
|
|||
newGreeting = 'new:greeting',
|
||||
}
|
||||
|
||||
export enum Model {
|
||||
gpt4 = 'gpt-4',
|
||||
gpt3_5 = 'gpt-3.5-turbo',
|
||||
}
|
||||
|
||||
export class Forefront extends Chat {
|
||||
private client: AxiosInstance | undefined;
|
||||
private session: ForefrontSessionInfo | undefined;
|
||||
private keepAliveInterval: NodeJS.Timer | undefined = undefined;
|
||||
|
||||
constructor(options?: ChatOptions) {
|
||||
super(options);
|
||||
|
@ -87,7 +95,7 @@ export class Forefront extends Chat {
|
|||
|
||||
}
|
||||
|
||||
public async askStream(req: Request): Promise<ResponseStream> {
|
||||
public async askStream(req: ForefrontRequest): Promise<ResponseStream> {
|
||||
if (!this.client) {
|
||||
await this.initClient();
|
||||
}
|
||||
|
@ -96,9 +104,9 @@ export class Forefront extends Chat {
|
|||
}
|
||||
const {
|
||||
chatId = v4(),
|
||||
actionType = 'new',
|
||||
actionType = Action.new,
|
||||
defaultPersona = '607e41fe-95be-497e-8e97-010a59b2e2c0',
|
||||
model = 'gpt-4',
|
||||
gptmodel = Model.gpt4,
|
||||
} = req.options || {};
|
||||
const jsonData = {
|
||||
text: req.prompt,
|
||||
|
@ -106,7 +114,7 @@ export class Forefront extends Chat {
|
|||
parentId: chatId,
|
||||
workspaceId: chatId,
|
||||
messagePersona: defaultPersona,
|
||||
model: model,
|
||||
model: gptmodel,
|
||||
};
|
||||
const base64Data = Buffer.from(this.session.userID + defaultPersona + chatId).toString('base64');
|
||||
const encryptedSignature = encryptWithAes256Cbc(base64Data, this.session.sessionID);
|
||||
|
@ -115,11 +123,21 @@ export class Forefront extends Chat {
|
|||
const response = await this.client?.post(
|
||||
'https://streaming.tenant-forefront-default.knative.chi.coreweave.com/chat', jsonData,
|
||||
{
|
||||
responseType: 'stream', headers: {'x-signature': encryptedSignature}
|
||||
responseType: 'stream', headers: {
|
||||
'x-signature': encryptedSignature, 'authorization': 'Bearer ' + this.session.token,
|
||||
}
|
||||
} as AxiosRequestConfig
|
||||
);
|
||||
return {text: response.data};
|
||||
} catch (e) {// session will expire very fast, I cannot know what reason
|
||||
} catch (e: any) {// session will expire very fast, I cannot know what reason
|
||||
if (e.response.status === 401) {
|
||||
if (req.options?.resignup) {
|
||||
this.client = undefined;
|
||||
// do not retry auto, avoid loss control
|
||||
throw new Error('retry again, will sign up again');
|
||||
}
|
||||
throw new Error('try change model to gpt-3.5-turbo or set resignup = true')
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
@ -132,7 +150,6 @@ export class Forefront extends Chat {
|
|||
'authority': 'chat-server.tenant-forefront-default.knative.chi.coreweave.com',
|
||||
'accept': '*/*',
|
||||
'accept-language': 'en,fr-FR;q=0.9,fr;q=0.8,es-ES;q=0.7,es;q=0.6,en-US;q=0.5,am;q=0.4,de;q=0.3',
|
||||
'authorization': 'Bearer ' + hisSession.token,
|
||||
'cache-control': 'no-cache',
|
||||
'content-type': 'application/json',
|
||||
'origin': 'https://chat.forefront.ai',
|
||||
|
@ -158,8 +175,8 @@ export class Forefront extends Chat {
|
|||
origin: 'https://accounts.forefront.ai',
|
||||
'user-agent': agent, // Replace with actual random user agent
|
||||
}
|
||||
if (this.proxy) {
|
||||
session.proxy = this.proxy;
|
||||
if (this.options?.proxy) {
|
||||
session.proxy = this.options.proxy;
|
||||
}
|
||||
const signEmailRes = await session.post('https://clerk.forefront.ai/v1/client/sign_ups?_clerk_js_version=4.38.4',
|
||||
{data: {'email_address': mailAddress}});
|
||||
|
@ -193,6 +210,16 @@ export class Forefront extends Chat {
|
|||
const token = (loginRes.data as any).response.sessions[0].last_active_token.jwt;
|
||||
const sessionID = (loginRes.data as any).response.sessions[0].id
|
||||
const userID = (loginRes.data as any).response.sessions[0].user.id
|
||||
this.keepAliveInterval = setInterval(async () => {
|
||||
try {
|
||||
const keepAliveRes = await session.post(`https://clerk.forefront.ai/v1/client/sessions/${sessionID}/tokens?_clerk_js_version=4.39.0`);
|
||||
if (this.session) {
|
||||
this.session.token = (keepAliveRes.data as any).jwt as string;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}, 30 * 1000);
|
||||
return {token, agent, sessionID, userID};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,8 +69,8 @@ export class You extends Chat {
|
|||
super(props);
|
||||
this.session = new tlsClient.Session({clientIdentifier: 'chrome_108'});
|
||||
this.session.headers = this.getHeaders();
|
||||
if (this.proxy) {
|
||||
this.session.proxy = this.proxy;
|
||||
if (this.options?.proxy) {
|
||||
this.session.proxy = this.options.proxy;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
読み込み中…
新しいイシューから参照