gpt4free-ts/model/hypotenuse/index.ts

260 行
6.9 KiB
TypeScript

import { Chat, ChatOptions, ChatRequest, ModelType } from '../base';
import {
Event,
EventStream,
getRandomOne,
randomStr,
sleep,
} from '../../utils';
import {
ChildOptions,
ComChild,
ComInfo,
DestroyOptions,
Pool,
} from '../../utils/pool';
import { Config } from '../../utils/config';
import { CreateNewAxios, CreateNewPage } from '../../utils/proxyAgent';
import { CreateEmail } from '../../utils/emailFactory';
import { Page } from 'puppeteer';
const ModelMap: Partial<Record<ModelType, string>> = {
[ModelType.GPT4]: '9675b1e8f62811eda0d10242ac130004',
[ModelType.GPT3p5Turbo]: 'e5aba828ebef11edb9980242ac130003',
};
interface Account extends ComInfo {
email: string;
password: string;
session: string;
}
class Child extends ComChild<Account> {
public page?: Page;
client = CreateNewAxios({
baseURL: 'https://app.hypotenuse.ai',
});
constructor(label: string, info: any, options?: ChildOptions) {
super(label, info, options);
}
async init(): Promise<void> {
try {
let page: Page;
this.logger.info('register new account ...');
page = await CreateNewPage(`https://app.hypotenuse.ai/home`, {
simplify: false,
});
await page.waitForSelector('div > p > a');
await page.click('div > p > a');
const mail = CreateEmail(Config.config.hypotenuse.mail_type);
await page.waitForSelector('#email');
await page.click('#email');
const email = await mail.getMailAddress();
await page.type('#email', email);
await page.waitForSelector('#password');
await page.click('#password');
const password = randomStr(getRandomOne([15, 20, 21, 22, 23, 24, 25]));
await page.type('#password', password);
await page.click("button[type='submit']");
let verifyURL = '';
for (const v of await mail.waitMails()) {
verifyURL = v.content.match(/href="https:\/\/dev(.+?)"/)?.[1] || '';
if (verifyURL) {
verifyURL = 'https://dev' + verifyURL;
break;
}
}
if (!verifyURL) {
throw new Error('verifyURL not found');
}
const newPage = await page.browser().newPage();
await newPage.goto(verifyURL);
await sleep(3000);
await newPage.close();
await page.bringToFront();
await page.waitForSelector(
'.dimmable > .MuiPaper-root.MuiPaper-elevation1',
);
await page.click('.dimmable > .MuiPaper-root.MuiPaper-elevation1');
await this.saveSess();
this.page = page;
} catch (e) {
throw e;
}
}
async createThreads() {
const { data } = await this.client.post(
'/chat/thread',
{},
{
headers: {
Cookie: `session=${this.info.session}`,
},
},
);
return data as {
id: string;
organization_id: string;
user_id: string;
created_at: number;
deleted: boolean;
deleted_at: number | null;
display_name: string | null;
};
}
async sendMessage(threadID: string, prompt: string) {
const { data } = await this.client.post(
`/chat/threads/${threadID}/messages`,
{
content: 'hello',
},
{
headers: {
Cookie: `session=${this.info.session}`,
},
},
);
return data as {
id: string;
thread_id: string;
user_id: string;
content: string;
is_generated: boolean;
created_at: number;
deleted: boolean;
deleted_at: number | null;
reply_to_id: string | null;
has_error_response: boolean;
intermediate_steps: any | null; // 如果有具体类型,可以替换 `any`
message_type: string;
metadata: Record<string, any>; // 如果有更具体的类型,可以进行替换
is_file_indexed: boolean | null;
summary: string | null;
sender_info: {
id: string;
display_name: string;
};
feedback_type: string | null;
};
}
async genRes(thrID: string, msgID: string, model: ModelType) {
const { data } = await this.client.post(
`/chat/threads/${thrID}/messages/${msgID}/generate-respons`,
{
is_enhanced_quality: model === ModelType.GPT4,
is_real_time_web_data: false,
},
{
headers: {
Cookie: `session=${this.info.session}`,
},
},
);
return data as {
id: string;
thread_id: string;
user_id: string;
content: string;
is_generated: boolean;
created_at: number;
deleted: boolean;
deleted_at: number | null;
reply_to_id: string | null;
has_error_response: boolean;
intermediate_steps: any[] | null; // 如果有具体类型,可以替换 `any`
message_type: string;
metadata: Record<string, any>; // 如果有更具体的类型,可以进行替换
is_file_indexed: boolean | null;
summary: string | null;
sender_info: {
id: string;
display_name: string;
};
feedback_type: string | null;
};
}
async saveSess() {
const cookies = await this.page?.cookies();
const session = cookies?.find((v) => v.name === 'session');
if (!session) {
throw new Error('session not found');
}
this.update({ session: session.value });
}
initFailed() {
this.page?.browser().close();
this.destroy({ delFile: true, delMem: true });
}
destroy(options?: DestroyOptions) {
super.destroy(options);
this.page?.browser()?.close();
}
}
export class Hypotenuse extends Chat {
private pool: Pool<Account, Child> = new Pool(
this.options?.name || '',
() => Config.config.hypotenuse.size,
(info, options) => {
return new Child(this.options?.name || '', info, options);
},
(v) => {
if (!v.session) {
return false;
}
return true;
},
{ delay: 1000, serial: () => Config.config.hypotenuse.serial || 1 },
);
constructor(options?: ChatOptions) {
super(options);
}
support(model: ModelType): number {
switch (model) {
case ModelType.GPT4:
return 5000;
case ModelType.GPT3p5Turbo:
return 3000;
case ModelType.GPT3p5_16k:
return 12000;
default:
return 0;
}
}
async preHandle(req: ChatRequest): Promise<ChatRequest> {
return super.preHandle(req, {
token: true,
countPrompt: false,
forceRemove: true,
});
}
async askStream(req: ChatRequest, stream: EventStream): Promise<void> {
const child = await this.pool.pop();
try {
const { id: thrID } = await child.createThreads();
const { id: msgID } = await child.sendMessage(thrID, req.prompt);
const res = await child.genRes(thrID, msgID, req.model);
stream.write(Event.message, { content: res.content });
stream.write(Event.done, { content: '' });
stream.end();
} catch (e: any) {
this.logger.error(e);
stream.write(Event.error, e.message);
stream.end();
child.destroy({ delFile: false, delMem: true });
}
}
}