likes
comments
collection
share

Electron+Exrepss.js 实现ChatGPT API调用

作者站长头像
站长
· 阅读数 51

当前OpenAI只开放了ChatGPT3.5的网页端的免费访问,同时新注册用户能免费使用3个月的API访问,到期收费。 这边想了个办法,使用Electron来操作网页,模拟发送/接收回答;express.js 做http服务器来供外部发送和接收消息。

  • 为什么使用electron? electron基于chromium,本质就是浏览器。使用electron可以很方便的在各个网页中注入js,执行我们需要的代码;同时各个网站在反爬虫的同时都需要尽可能保证用户的正常访问,而electron会完整渲染页面,因此electron相比传统的爬虫操作更直观,成功率更高。

准备工作

克隆electron-quick-start,用于快速构建electron项目

git clone https://github.com/electron/electron-quick-start`
npm i

安装express.js

npm i express

开发

编辑main.js,加入以下内容:

  • 使用express注册连个接口,分别用来向网页发送消息和获取网页中的会话内容
  • 注册electron的ipc通讯,用来向渲染进程发送消息,操作网页
  • 使用代理访问chatgpt的官网 源码:
const { app, BrowserWindow, Menu, ipcMain } = require('electron')
const path = require('node:path')
const express = require('express')
var bodyParser = require('body-parser')
var jsonParser = bodyParser.json()

current_dialogs = []

function jsonMessage(msg) {
  return { msg: msg }
}

function AppServer(sendMessage = (msg) => { console.log(msg) }, port = 3000) {
  const app = express()
  let server = null
  app.post("/send", jsonParser, function (req, res) {
    try {
      const msg = req.body.msg
      sendMessage(msg)
      res.json(jsonMessage('ok'))
    } catch (e) {
      console.error(e)
      res.status(400)
      res.json(jsonMessage("bad request"))
    }
  })
  app.get("/dialogs", function (req, res) {
    res.json({ dialogs: current_dialogs })
  })
  return {
    close: function () {
      if (server) server.close()
    },
    start: function () {
      server = app.listen(port)
    }
  }
}

function createMenu(window) {
  return Menu.buildFromTemplate(
    [
      {
        label: '选项',
        submenu: [
          {
            label: '打开控制台',
            click: () => { window.webContents.openDevTools() }
          },
          {
            label: '刷新',
            click: () => { window.reload() }
          }
        ]
      }
    ])
}

function createWindow() {
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js')
    }
  })
  const menu = createMenu(mainWindow)
  mainWindow.setMenu(menu)
  ipcMain.on('receive-dialogs', (event, dialogs) => {
    current_dialogs = dialogs
  })
  mainWindow.webContents.session.setProxy({ proxyRules: "socks5://127.0.0.1:7890" })
    .then(() => { mainWindow.loadURL('https://chatgpt.com/') })
  let server = AppServer((msg) => {mainWindow.webContents.send('new-msg', msg)})
  server.start()
}

app.whenReady().then(() => {
  createWindow()
  app.on('activate', function () {
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
})

app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') app.quit()
})

编辑preload.js,加入以下内容:

  • chatgpt的发送按钮是响应输入框变动的事件的,但是通过js直接操作输入框的元素改变值无法响应该事件。通过增加EVENT和dispatchEvent来触发该响应。(stackoverflow.com/questions/6…
  • 注册ipc事件,接收主线程中的消息,操作网页。
  • 一个 getDialogsTimer 定时器,每秒获取当前网页中的会话,发送到主线程。
const { ipcRenderer } = require('electron/renderer')
const EVENT_OPTIONS = { bubbles: true, cancelable: false, composed: true };
const EVENTS = {
  BLUR: new Event("blur", EVENT_OPTIONS),
  CHANGE: new Event("change", EVENT_OPTIONS),
  INPUT: new Event("input", EVENT_OPTIONS),
};

ipcRenderer.on('new-msg', (sender, msg) => {
  const inputElement = document.querySelectorAll('textarea')[0]
  inputElement.value = msg;
  inputElement.dispatchEvent(EVENTS.INPUT);
  document.querySelectorAll('button')[document.querySelectorAll('button').length-2].click()
})

function sleep(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms)
  })
}

async function getDialogsTimer() {
  for (; ;) {
    await sleep(1000)
    var dialogs = []
    for (let o of document.querySelectorAll('p')) {
      dialogs.push(o.innerHTML)
    }
    ipcRenderer.send('receive-dialogs', dialogs)
  }
}

getDialogsTimer()

效果

  • 使用/send 发送消息
  • 使用/dialogs 获取消息 Electron+Exrepss.js 实现ChatGPT API调用

发送和接收的内容会同步显示在网页端:

Electron+Exrepss.js 实现ChatGPT API调用

目前还在原型阶段,还有一些优化点:

  • electron内存较大
  • 多个对话需要多进程/多端口
  • 需要获取对话是否结束

项目地址: github.com/AlpsMonaco/…

转载自:https://juejin.cn/post/7385784332444991499
评论
请登录