monra commited on
Commit
f6647c3
1 Parent(s): 421ae07

Update GPT-4 API from: xiangsx/gpt4free-ts/

Browse files
apiGPT4/.github/workflows/docker-image.yml DELETED
@@ -1,37 +0,0 @@
1
- # docker-image.yml
2
- name: Publish Docker image # workflow名称,可以在Github项目主页的【Actions】中看到所有的workflow
3
-
4
- on: # 配置触发workflow的事件
5
- push:
6
- tags: # tag更新时触发此workflow
7
- - '*'
8
-
9
- jobs: # workflow中的job
10
-
11
- push_to_registry: # job的名字
12
- name: Push Docker image to Docker Hub
13
- runs-on: ubuntu-latest # job运行的基础环境
14
-
15
- steps: # 一个job由一个或多个step组成
16
- - name: Check out the repo
17
- uses: actions/checkout@v2 # 官方的action,获取代码
18
-
19
- - name: Log in to Docker Hub
20
- uses: docker/login-action@v1 # 三方的action操作, 执行docker login
21
- with:
22
- username: ${{ secrets.DOCKERHUB_USERNAME }} # 配置dockerhub的认证,在Github项目主页 【Settings】 -> 【Secrets】 添加对应变量
23
- password: ${{ secrets.DOCKERHUB_TOKEN }}
24
-
25
- - name: Extract metadata (tags, labels) for Docker
26
- id: meta
27
- uses: docker/metadata-action@v3 # 抽取项目信息,主要是镜像的tag
28
- with:
29
- images: xiangsx/gpt4free-ts
30
-
31
- - name: Build and push Docker image
32
- uses: docker/build-push-action@v2 # docker build & push
33
- with:
34
- context: .
35
- push: true
36
- tags: ${{ steps.meta.outputs.tags }}
37
- labels: ${{ steps.meta.outputs.labels }}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
apiGPT4/model/forefront/index.ts CHANGED
@@ -1,6 +1,6 @@
1
  import {Chat, ChatOptions, Request, Response, ResponseStream} from "../base";
2
  import {Browser, Page} from "puppeteer";
3
- import {BrowserPool} from "../../pool/puppeteer";
4
  import {CreateEmail, TempEmailType, TempMailMessage} from "../../utils/emailFactory";
5
  import {CreateTlsProxy} from "../../utils/proxyAgent";
6
  import * as fs from "fs";
@@ -87,7 +87,7 @@ class AccountPool {
87
  }
88
 
89
 
90
- export class Forefrontnew extends Chat {
91
  private pagePool: BrowserPool<Account>;
92
  private accountPool: AccountPool;
93
 
@@ -95,8 +95,7 @@ export class Forefrontnew extends Chat {
95
  super(options);
96
  this.accountPool = new AccountPool();
97
  const maxSize = +(process.env.POOL_SIZE || 2);
98
- const initialAccounts = this.accountPool.multiGet(maxSize);
99
- this.pagePool = new BrowserPool<Account>(maxSize, initialAccounts.map(item => item.id), this.init.bind(this));
100
  }
101
 
102
  public async ask(req: Request): Promise<Response> {
@@ -139,8 +138,30 @@ export class Forefrontnew extends Chat {
139
  }
140
 
141
  private static async closeVIPPop(page: Page) {
142
- await page.waitForSelector('.flex > .w-full:nth-child(1) > .grid:nth-child(2) > .flex > .text-sm')
143
- await page.click('.flex > .w-full:nth-child(1) > .grid:nth-child(2) > .flex > .text-sm')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  }
145
 
146
  private static async selectAssistant(page: Page) {
@@ -209,7 +230,7 @@ export class Forefrontnew extends Chat {
209
  }));
210
  }
211
 
212
- private async init(id: string, browser: Browser): Promise<[Page | undefined, Account, string]> {
213
  const account = this.accountPool.getByID(id);
214
  try {
215
  if (!account) {
@@ -223,7 +244,7 @@ export class Forefrontnew extends Chat {
223
  await Forefrontnew.closeVIPPop(page);
224
  await Forefrontnew.switchToGpt4(page);
225
  await this.allowClipboard(browser, page);
226
- return [page, account, account.id];
227
  }
228
  await page.goto("https://accounts.forefront.ai/sign-up");
229
  await page.setViewport({width: 1920, height: 1080});
@@ -256,18 +277,15 @@ export class Forefrontnew extends Chat {
256
  console.log('register successfully');
257
  account.login_time = moment().format(TimeFormat);
258
  this.accountPool.syncfile();
259
- await page.waitForSelector('.flex > .modal > .modal-box > .flex > .px-3:nth-child(1)', {timeout: 120000})
260
- await page.click('.flex > .modal > .modal-box > .flex > .px-3:nth-child(1)')
261
  await Forefrontnew.closeVIPPop(page);
262
  await page.waitForSelector('.relative > .flex > .w-full > .text-th-primary-dark > div', {timeout: 120000})
263
  await Forefrontnew.switchToGpt4(page);
264
  await this.allowClipboard(browser, page);
265
- return [page, account, account.id];
266
  } catch (e) {
267
  console.warn('something error happened,err:', e);
268
- this.accountPool.delete(account?.id || "")
269
- const newAccount = this.accountPool.get();
270
- return [undefined, this.accountPool.get(), newAccount.id] as any;
271
  }
272
  }
273
 
@@ -301,8 +319,7 @@ export class Forefrontnew extends Chat {
301
  const md = mdList;
302
  } catch (e) {
303
  console.error(e);
304
- const newAccount = this.accountPool.get();
305
- destroy(newAccount.id);
306
  pt.write("error", 'some thing error, try again later');
307
  pt.end();
308
  return {text: pt.stream}
@@ -346,8 +363,7 @@ export class Forefrontnew extends Chat {
346
  account.gpt4times = 0;
347
  account.last_use_time = moment().format(TimeFormat);
348
  this.accountPool.syncfile();
349
- const newAccount = this.accountPool.get();
350
- destroy(newAccount.id);
351
  } else {
352
  done(account);
353
  }
 
1
  import {Chat, ChatOptions, Request, Response, ResponseStream} from "../base";
2
  import {Browser, Page} from "puppeteer";
3
+ import {BrowserPool, BrowserUser} from "../../pool/puppeteer";
4
  import {CreateEmail, TempEmailType, TempMailMessage} from "../../utils/emailFactory";
5
  import {CreateTlsProxy} from "../../utils/proxyAgent";
6
  import * as fs from "fs";
 
87
  }
88
 
89
 
90
+ export class Forefrontnew extends Chat implements BrowserUser<Account>{
91
  private pagePool: BrowserPool<Account>;
92
  private accountPool: AccountPool;
93
 
 
95
  super(options);
96
  this.accountPool = new AccountPool();
97
  const maxSize = +(process.env.POOL_SIZE || 2);
98
+ this.pagePool = new BrowserPool<Account>(maxSize, this);
 
99
  }
100
 
101
  public async ask(req: Request): Promise<Response> {
 
138
  }
139
 
140
  private static async closeVIPPop(page: Page) {
141
+ try {
142
+ await page.waitForSelector('.flex > .w-full:nth-child(1) > .grid:nth-child(2) > .flex > .text-sm', {timeout: 15 * 1000})
143
+ await page.click('.flex > .w-full:nth-child(1) > .grid:nth-child(2) > .flex > .text-sm')
144
+ } catch (e) {
145
+ console.log('not need close vip');
146
+ }
147
+ }
148
+
149
+ private static async closeWelcomePop(page: Page) {
150
+ try {
151
+ await page.waitForSelector('.flex > .modal > .modal-box > .flex > .px-3:nth-child(1)', {timeout: 120 * 1000})
152
+ await page.click('.flex > .modal > .modal-box > .flex > .px-3:nth-child(1)')
153
+ } catch (e) {
154
+ console.log('not need close welcome pop');
155
+ }
156
+ }
157
+
158
+ deleteID(id: string): void {
159
+ this.accountPool.delete(id);
160
+ }
161
+
162
+ newID(): string {
163
+ const account = this.accountPool.get();
164
+ return account.id;
165
  }
166
 
167
  private static async selectAssistant(page: Page) {
 
230
  }));
231
  }
232
 
233
+ async init(id: string, browser: Browser): Promise<[Page | undefined, Account]> {
234
  const account = this.accountPool.getByID(id);
235
  try {
236
  if (!account) {
 
244
  await Forefrontnew.closeVIPPop(page);
245
  await Forefrontnew.switchToGpt4(page);
246
  await this.allowClipboard(browser, page);
247
+ return [page, account];
248
  }
249
  await page.goto("https://accounts.forefront.ai/sign-up");
250
  await page.setViewport({width: 1920, height: 1080});
 
277
  console.log('register successfully');
278
  account.login_time = moment().format(TimeFormat);
279
  this.accountPool.syncfile();
280
+ await Forefrontnew.closeWelcomePop(page);
 
281
  await Forefrontnew.closeVIPPop(page);
282
  await page.waitForSelector('.relative > .flex > .w-full > .text-th-primary-dark > div', {timeout: 120000})
283
  await Forefrontnew.switchToGpt4(page);
284
  await this.allowClipboard(browser, page);
285
+ return [page, account];
286
  } catch (e) {
287
  console.warn('something error happened,err:', e);
288
+ return [] as any;
 
 
289
  }
290
  }
291
 
 
319
  const md = mdList;
320
  } catch (e) {
321
  console.error(e);
322
+ destroy();
 
323
  pt.write("error", 'some thing error, try again later');
324
  pt.end();
325
  return {text: pt.stream}
 
363
  account.gpt4times = 0;
364
  account.last_use_time = moment().format(TimeFormat);
365
  this.accountPool.syncfile();
366
+ destroy();
 
367
  } else {
368
  done(account);
369
  }
apiGPT4/pool/puppeteer.ts CHANGED
@@ -17,63 +17,88 @@ export interface PageInfo<T> {
17
  data?: T;
18
  }
19
 
20
- type PrepareFunc<T> = (id: string, browser: Browser) => Promise<[Page | undefined, T, string]>
 
 
 
 
 
 
21
 
22
  export class BrowserPool<T> {
23
  private readonly pool: PageInfo<T>[] = [];
24
  private readonly size: number;
25
- private readonly prepare: PrepareFunc<T>
26
 
27
- constructor(size: number, initialIDs: string[], prepare: PrepareFunc<T>) {
28
  this.size = size
29
- this.prepare = prepare;
30
- this.init(initialIDs);
31
  }
32
 
33
- init(initialIDs: string[]) {
34
  for (let i = 0; i < this.size; i++) {
35
- const id = initialIDs[i];
36
  const info: PageInfo<T> = {
37
  id,
38
  ready: false,
39
  }
40
- this.initOne(id).then(([page, data, newID]) => {
41
- if (!page) {
42
- return;
43
- }
44
- info.id = newID;
45
- info.page = page;
46
- info.data = data;
47
- info.ready = true;
48
- }).catch(e => {
49
- console.error(e);
50
- })
51
  this.pool.push(info)
 
 
 
 
 
 
 
 
 
52
  }
53
  }
54
 
55
- async initOne(id: string): Promise<[Page, T, string]> {
 
 
 
 
 
56
  const options: PuppeteerLaunchOptions = {
57
  headless: process.env.DEBUG === "1" ? false : 'new',
58
  args: ['--no-sandbox', '--disable-setuid-sandbox'],
59
- userDataDir: `run/${id}`,
60
  };
61
- const browser = await puppeteer.launch(options);
62
- const [page, data, newID] = await this.prepare(id, browser)
63
- if (!page) {
64
- console.log(`init ${id} failed, delete! init new ${newID}`);
65
- await browser.close();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  if (options.userDataDir) {
67
  fs.rmdirSync(options.userDataDir, {recursive: true});
68
  }
69
  await sleep(5000);
70
- return this.initOne(newID);
 
71
  }
72
- return [page, data, newID];
73
  }
74
 
75
  //@ts-ignore
76
- get(): [page: Page | undefined, data: T | undefined, done: (data: T) => void, destroy: (newID: string) => void] {
77
  for (const item of shuffleArray(this.pool)) {
78
  if (item.ready) {
79
  item.ready = false;
@@ -84,14 +109,11 @@ export class BrowserPool<T> {
84
  item.ready = true
85
  item.data = data;
86
  },
87
- (newID: string) => {
88
  item.page?.close();
89
- this.initOne(newID).then(([page, data, newID]) => {
90
- item.id = newID;
91
- item.page = page
92
- item.data = data;
93
- item.ready = true;
94
- })
95
  }
96
  ]
97
  }
 
17
  data?: T;
18
  }
19
 
20
+ type PrepareFunc<T> = (id: string, browser: Browser) => Promise<[Page | undefined, T]>
21
+
22
+ export interface BrowserUser<T> {
23
+ init: PrepareFunc<T>;
24
+ newID: () => string
25
+ deleteID: (id: string) => void
26
+ }
27
 
28
  export class BrowserPool<T> {
29
  private readonly pool: PageInfo<T>[] = [];
30
  private readonly size: number;
31
+ private readonly user: BrowserUser<T>
32
 
33
+ constructor(size: number, user: BrowserUser<T>) {
34
  this.size = size
35
+ this.user = user;
36
+ this.init();
37
  }
38
 
39
+ init() {
40
  for (let i = 0; i < this.size; i++) {
41
+ const id = this.user.newID();
42
  const info: PageInfo<T> = {
43
  id,
44
  ready: false,
45
  }
 
 
 
 
 
 
 
 
 
 
 
46
  this.pool.push(info)
47
+ this.initOne(id).then()
48
+ }
49
+ }
50
+
51
+ find(id: string): PageInfo<T> | undefined {
52
+ for (const info of this.pool) {
53
+ if (info.id === id) {
54
+ return info;
55
+ }
56
  }
57
  }
58
 
59
+ async initOne(id: string): Promise<void> {
60
+ const info = this.find(id);
61
+ if (!info) {
62
+ console.error('init one failed, not found info');
63
+ return;
64
+ }
65
  const options: PuppeteerLaunchOptions = {
66
  headless: process.env.DEBUG === "1" ? false : 'new',
67
  args: ['--no-sandbox', '--disable-setuid-sandbox'],
68
+ userDataDir: `run/${info.id}`,
69
  };
70
+ try {
71
+ const browser = await puppeteer.launch(options);
72
+ const [page, data] = await this.user.init(info.id, browser);
73
+ if (!page) {
74
+ const newID = this.user.newID();
75
+ console.warn(`init ${info.id} failed, delete! init new ${newID}`);
76
+ await browser.close();
77
+ if (options.userDataDir) {
78
+ fs.rmdirSync(options.userDataDir, {recursive: true});
79
+ }
80
+ await sleep(5000);
81
+ info.id = newID;
82
+ return await this.initOne(info.id);
83
+ }
84
+ info.page = page;
85
+ info.data = data
86
+ info.ready = true;
87
+ } catch (e) {
88
+ console.error('init one failed, err:', e);
89
+ const newID = this.user.newID();
90
+ console.warn(`init ${info.id} failed, delete! init new ${newID}`);
91
  if (options.userDataDir) {
92
  fs.rmdirSync(options.userDataDir, {recursive: true});
93
  }
94
  await sleep(5000);
95
+ info.id = newID;
96
+ return await this.initOne(info.id);
97
  }
 
98
  }
99
 
100
  //@ts-ignore
101
+ get(): [page: Page | undefined, data: T | undefined, done: (data: T) => void, destroy: () => void] {
102
  for (const item of shuffleArray(this.pool)) {
103
  if (item.ready) {
104
  item.ready = false;
 
109
  item.ready = true
110
  item.data = data;
111
  },
112
+ () => {
113
  item.page?.close();
114
+ this.user.deleteID(item.id);
115
+ item.id = this.user.newID();
116
+ this.initOne(item.id).then();
 
 
 
117
  }
118
  ]
119
  }