forked from xiangsx/gpt4free-ts
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
366 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
//@ts-ignore | ||
import UserAgent from 'user-agents'; | ||
import tlsClient from 'tls-client'; | ||
|
||
import {Chat, ChatOptions, Request, Response, ResponseStream} from "../base"; | ||
import {Email} from '../../utils/email'; | ||
import axios, {AxiosInstance, CreateAxiosDefaults} from "axios"; | ||
import {v4} from "uuid"; | ||
import es from "event-stream"; | ||
import {parseJSON} from "../../utils"; | ||
|
||
interface ForefrontRequest extends Request { | ||
options?: { | ||
chatId?: string; | ||
prompt?: string; | ||
actionType?: string; | ||
defaultPersona?: string; | ||
model?: string; | ||
} | ||
} | ||
|
||
interface ChatCompletionChoice { | ||
delta: { | ||
content: string; | ||
}; | ||
index: number; | ||
finish_reason: string | null; | ||
} | ||
|
||
interface ChatCompletionChunk { | ||
id: string; | ||
object: string; | ||
created: number; | ||
model: string; | ||
choices: ChatCompletionChoice[]; | ||
} | ||
|
||
interface ForefrontSessionInfo { | ||
agent: string; | ||
token: string; | ||
} | ||
|
||
export class Forefront extends Chat { | ||
private client: AxiosInstance | undefined; | ||
|
||
constructor(options?: ChatOptions) { | ||
super(options); | ||
this.client = undefined; | ||
} | ||
|
||
public async ask(req: ForefrontRequest): Promise<Response> { | ||
const res = await this.askStream(req); | ||
let text = ''; | ||
return new Promise(resolve => { | ||
res.text.pipe(es.split(/\r?\n\r?\n/)).pipe(es.map(async (chunk: any, cb: any) => { | ||
const str = chunk.replace('data: ', ''); | ||
const data = parseJSON(str, {}) as ChatCompletionChunk; | ||
if (!data.choices) { | ||
cb(null, ''); | ||
return; | ||
} | ||
const [{delta: {content}}] = data.choices; | ||
cb(null, content); | ||
})).on('data', (data) => { | ||
text += data; | ||
}).on('close', () => { | ||
resolve({text, other: res.other}); | ||
}) | ||
}) | ||
|
||
} | ||
|
||
public async askStream(req: Request): Promise<ResponseStream> { | ||
if (!this.client) { | ||
await this.initClient(); | ||
} | ||
if (!this.client) { | ||
throw new Error('hava not created account'); | ||
} | ||
const { | ||
chatId = v4(), | ||
actionType = 'new', | ||
defaultPersona = '607e41fe-95be-497e-8e97-010a59b2e2c0', | ||
model = 'gpt-4', | ||
} = req.options || {}; | ||
const jsonData = { | ||
text: req.prompt, | ||
action: actionType, | ||
parentId: chatId, | ||
workspaceId: chatId, | ||
messagePersona: defaultPersona, | ||
model: model, | ||
}; | ||
|
||
try { | ||
const response = await this.client?.post( | ||
'https://chat-server.tenant-forefront-default.knative.chi.coreweave.com/chat', | ||
jsonData, | ||
{responseType: 'stream'} | ||
); | ||
return {text: response.data}; | ||
} catch (e) {// session will expire very fast, I cannot know what reason | ||
throw e; | ||
} | ||
} | ||
|
||
async initClient() { | ||
let hisSession = await this.createToken(); | ||
this.client = axios.create({ | ||
headers: { | ||
'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', | ||
'pragma': 'no-cache', | ||
'referer': 'https://chat.forefront.ai/', | ||
'sec-ch-ua': '"Chromium";v="112", "Google Chrome";v="112", "Not:A-Brand";v="99"', | ||
'sec-ch-ua-mobile': '?0', | ||
'sec-ch-ua-platform': '"macOS"', | ||
'sec-fetch-dest': 'empty', | ||
'sec-fetch-mode': 'cors', | ||
'sec-fetch-site': 'cross-site', | ||
'user-agent': hisSession.agent, | ||
} | ||
} as CreateAxiosDefaults); | ||
} | ||
|
||
async createToken(): Promise<ForefrontSessionInfo> { | ||
const mailbox = new Email(); | ||
const mailAddress = await mailbox.create(); | ||
const agent = new UserAgent().toString(); | ||
const session = new tlsClient.Session({clientIdentifier: 'chrome_108'}); | ||
session.headers = { | ||
origin: 'https://accounts.forefront.ai', | ||
'user-agent': agent, // Replace with actual random user agent | ||
} | ||
if (this.proxy) { | ||
session.proxy = this.proxy; | ||
} | ||
const signEmailRes = await session.post('https://clerk.forefront.ai/v1/client/sign_ups?_clerk_js_version=4.38.4', | ||
{data: {'email_address': mailAddress}}); | ||
const traceToken = (signEmailRes.data as any)?.response?.id; | ||
if (!traceToken) { | ||
throw new Error('Failed to create account! sign email res parse token failed!'); | ||
} | ||
|
||
const verifyRes = await session.post(`https://clerk.forefront.ai/v1/client/sign_ups/${traceToken}/prepare_verification?_clerk_js_version=4.38.4`, { | ||
data: { | ||
'strategy': 'email_link', | ||
'redirect_url': 'https://accounts.forefront.ai/sign-up/verify' | ||
}, | ||
}) | ||
if (verifyRes.text.indexOf('sign_up_attempt') === -1) { | ||
throw new Error('forefront create account failed'); | ||
} | ||
const msgs = await mailbox.getMessage() | ||
let validateURL: string | undefined; | ||
for (const msg of msgs) { | ||
validateURL = msg.mail_html.match(/https:\/\/clerk\.forefront\.ai\/v1\/verify\?token=[^\s"]+/i)?.[0]; | ||
if (validateURL) { | ||
break; | ||
} | ||
} | ||
if (!validateURL) { | ||
throw new Error('Error while obtaining verfication URL!') | ||
} | ||
const validateRes = await session.get(validateURL) | ||
const loginRes = await session.get('https://clerk.forefront.ai/v1/client?_clerk_js_version=4.38.4'); | ||
const token = (loginRes.data as any).response.sessions[0].last_active_token.jwt; | ||
return {token, agent}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import axios, {AxiosInstance, CreateAxiosDefaults} from 'axios'; | ||
import {md5, randomStr} from "./index"; | ||
|
||
export class Email { | ||
private mail: TempMail; | ||
private address: string | undefined; | ||
private domainList: string[]; | ||
private mailID: string; | ||
|
||
constructor() { | ||
this.mail = new TempMail(process.env.rapid_api_key || ""); | ||
this.address = undefined; | ||
this.mailID = ''; | ||
this.domainList = []; | ||
} | ||
|
||
async create(): Promise<any> { | ||
this.domainList = await this.mail.getDomainsList(); | ||
this.address = `${randomStr()}${this.randomDomain()}`; | ||
this.mailID = md5(this.address); | ||
return this.address; | ||
} | ||
|
||
randomDomain(): string { | ||
return this.domainList[Math.floor(Math.random() * this.domainList.length)]; | ||
} | ||
|
||
emailAddress() { | ||
if (!this.address) { | ||
throw new Error('create first'); | ||
} | ||
return this.address; | ||
} | ||
|
||
async getMessage() { | ||
return this.mail.getEmail(this.mailID); | ||
} | ||
} | ||
|
||
interface TempMailMessage { | ||
_id: { | ||
oid: string; | ||
}; | ||
createdAt: { | ||
milliseconds: number; | ||
}; | ||
mail_id: string; | ||
mail_address_id: string; | ||
mail_from: string; | ||
mail_subject: string; | ||
mail_preview: string; | ||
mail_text_only: string; | ||
mail_text: string; | ||
mail_html: string; | ||
mail_timestamp: number; | ||
mail_attachments_count: number; | ||
mail_attachments: { | ||
attachment: any[]; | ||
}; | ||
} | ||
|
||
class TempMail { | ||
private readonly client: AxiosInstance; | ||
|
||
constructor(apikey: string) { | ||
this.client = axios.create({ | ||
baseURL: 'https://privatix-temp-mail-v1.p.rapidapi.com/request/', | ||
headers: { | ||
'X-RapidAPI-Key': apikey, | ||
'X-RapidAPI-Host': 'privatix-temp-mail-v1.p.rapidapi.com' | ||
} | ||
} as CreateAxiosDefaults); | ||
} | ||
|
||
async getEmail(md5Str: string): Promise<TempMailMessage[]> { | ||
return new Promise(resolve => { | ||
let time = 0; | ||
const itl = setInterval(async () => { | ||
const response = await this.client.get(`/mail/id/${md5Str}`); | ||
if (response.data && response.data.length > 0) { | ||
resolve(response.data); | ||
clearInterval(itl); | ||
return; | ||
} | ||
if (time > 5) { | ||
resolve([]); | ||
clearInterval(itl); | ||
return; | ||
} | ||
time++; | ||
}, 1000); | ||
}); | ||
} | ||
|
||
async getDomainsList(): Promise<string[]> { | ||
const res = await this.client.get(`/domains/`); | ||
return res.data; | ||
} | ||
} |
Oops, something went wrong.