├── .gitignore
├── assets
├── icons
│ ├── mac
│ │ └── favicon.icns
│ ├── png
│ │ └── favicon.png
│ └── win
│ │ └── favicon.ico
├── css
│ ├── style.css
│ └── no-topbar.css
└── js
│ └── renderer.js
├── screenshots
└── screenshot-1.png
├── preload.js
├── src
├── view.js
├── print.js
├── window.js
└── menu.js
├── main.js
├── index.html
├── LICENSE
├── package.json
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | release-builds/
3 | node_modules/
--------------------------------------------------------------------------------
/assets/icons/mac/favicon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mantreshkhurana/ChatGPT-electron/HEAD/assets/icons/mac/favicon.icns
--------------------------------------------------------------------------------
/assets/icons/png/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mantreshkhurana/ChatGPT-electron/HEAD/assets/icons/png/favicon.png
--------------------------------------------------------------------------------
/assets/icons/win/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mantreshkhurana/ChatGPT-electron/HEAD/assets/icons/win/favicon.ico
--------------------------------------------------------------------------------
/screenshots/screenshot-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mantreshkhurana/ChatGPT-electron/HEAD/screenshots/screenshot-1.png
--------------------------------------------------------------------------------
/assets/css/style.css:
--------------------------------------------------------------------------------
1 | /* Main */
2 |
3 | body {
4 | margin: 0;
5 | padding: 0;
6 | -webkit-user-select: none;
7 | -webkit-app-region: drag;
8 | }
9 |
--------------------------------------------------------------------------------
/preload.js:
--------------------------------------------------------------------------------
1 | const { contextBridge, ipcRenderer } = require("electron");
2 |
3 | contextBridge.exposeInMainWorld("electron", {
4 | print: (arg) => ipcRenderer.invoke("print", arg),
5 | });
6 |
--------------------------------------------------------------------------------
/assets/css/no-topbar.css:
--------------------------------------------------------------------------------
1 | /* No topbar */
2 |
3 | #webview {
4 | position: absolute;
5 | top: 0;
6 | left: 0;
7 | width: 100%;
8 | height: 100%;
9 | display: inline-flex !important;
10 | }
11 |
--------------------------------------------------------------------------------
/src/view.js:
--------------------------------------------------------------------------------
1 | const electron = require("electron");
2 | const { BrowserView } = electron;
3 |
4 | exports.createBrowserView = (mainWindow) => {
5 | const view = new BrowserView();
6 | mainWindow.setBrowserView(view);
7 | view.setBounds({ x: 0, y: 0, width: 1024, height: 768 });
8 | view.webContents.loadURL("https://chat.openai.com/chat");
9 | };
10 |
--------------------------------------------------------------------------------
/src/print.js:
--------------------------------------------------------------------------------
1 | const { ipcMain, BrowserWindow } = require("electron");
2 |
3 | ipcMain.handle("print", async (event, arg) => {
4 | let printWindow = new BrowserWindow({ "auto-hide-menu-bar": true });
5 | printWindow.loadURL(arg);
6 |
7 | printWindow.webContents.on("did-finish-load", () => {
8 | printWindow.webContents.print();
9 | });
10 | });
11 |
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | const { app } = require("electron");
2 |
3 | app.allowRendererProcessReuse = true;
4 | app.on("ready", () => {
5 | const window = require("./src/window");
6 | mainWindow = window.createBrowserWindow(app);
7 |
8 | mainWindow.loadURL(`file://${__dirname}/index.html`, { userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36' });
9 |
10 | require("./src/print");
11 | });
12 |
13 | app.on("window-all-closed", () => {
14 | app.quit();
15 | });
16 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
10 |
11 |
12 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/window.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const { BrowserWindow } = require("electron");
3 |
4 | exports.createBrowserWindow = () => {
5 | return new BrowserWindow({
6 | width: 1024,
7 | height: 768,
8 | minWidth: 400,
9 | minHeight: 600,
10 | icon: path.join(__dirname, "assets/icons/png/favicon.png"),
11 | backgroundColor: "#fff",
12 | autoHideMenuBar: true,
13 | webPreferences: {
14 | devTools: false,
15 | contextIsolation: true,
16 | webviewTag: true,
17 | preload: path.join(__dirname, "../preload.js"),
18 | enableRemoteModule: true,
19 | nodeIntegration: false,
20 | nativeWindowOpen: true,
21 | webSecurity: true,
22 | allowRunningInsecureContent: true
23 | },
24 | });
25 | };
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Mantresh Khurana
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chatgpt-app",
3 | "productName": "ChatGPT",
4 | "version": "1.0.0",
5 | "description": "ChatGPT is a chatbot that uses GPT-3 to generate responses to your messages. It is a desktop application built with Electron.",
6 | "main": "main.js",
7 |
8 | "scripts": {
9 | "start": "electron .",
10 | "package-mac": "npx electron-packager . --overwrite --platform=darwin --arch=x64 --icon=assets/icons/mac/favicon.icns --prune=true --out=release-builds",
11 | "package-win": "npx electron-packager . --overwrite --asar=true --platform=win32 --arch=x64 --icon=assets/icons/win/favicon.ico --prune=true --out=release-builds --version-string.CompanyName=CE --version-string.FileDescription=CE --version-string.ProductName=\"ChatGPT\"",
12 | "package-linux": "npx electron-packager . --overwrite --platform=linux --arch=x64 --icon=assets/icons/png/favicon.png --prune=true --out=release-builds"
13 | },
14 |
15 | "repository": "https://github.com/mantreshkhurana/ChatGPT-electron",
16 | "author": "Mantresh Khurana",
17 | "license": "MIT",
18 |
19 | "devDependencies": {
20 | "electron": "^22.0.0"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/assets/js/renderer.js:
--------------------------------------------------------------------------------
1 | const getControlsHeight = () => {
2 | const controls = document.querySelector("#controls");
3 | if (controls) {
4 | return controls.offsetHeight;
5 | }
6 | return 0;
7 | };
8 |
9 | const calculateLayoutSize = () => {
10 | const webview = document.querySelector("webview");
11 | const windowWidth = document.documentElement.clientWidth;
12 | const windowHeight = document.documentElement.clientHeight;
13 | const controlsHeight = getControlsHeight();
14 | const webviewHeight = windowHeight - controlsHeight;
15 |
16 | webview.style.width = windowWidth + "px";
17 | webview.style.height = webviewHeight + "px";
18 | };
19 |
20 | window.addEventListener("DOMContentLoaded", () => {
21 | calculateLayoutSize();
22 |
23 | // Dynamic resize function (responsive)
24 | window.onresize = calculateLayoutSize;
25 |
26 | // Home button exists
27 | if (document.querySelector("#home")) {
28 | document.querySelector("#home").onclick = () => {
29 | const home = document.getElementById("webview").getAttribute("data-home");
30 | document.querySelector("webview").src = home;
31 | };
32 | }
33 |
34 | // Print button exits
35 | if (document.querySelector("#print_button")) {
36 | document
37 | .querySelector("#print_button")
38 | .addEventListener("click", async () => {
39 | const url = document.querySelector("webview").getAttribute("src");
40 |
41 | // Launch print window
42 | await window.electron.print(url);
43 | });
44 | }
45 | });
46 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # ChatGPT Desktop App
4 |
5 | 
6 |
7 | This is a desktop app for [ChatGPT](https://chat.openai.com/), a chatbot that uses GPT-3 to have conversations with you.
8 |
9 | 
10 |
11 | ## Downloads
12 |
13 | - [Windows (90 MB)](https://github.com/mantreshkhurana/ChatGPT-electron/releases/download/1.0.0/ChatGPT-v1.0.0-windows.zip)
14 | - [macOS (84 MB)](https://github.com/mantreshkhurana/ChatGPT-electron/releases/download/1.0.0/ChatGPT-v1.0.0-darwin.zip)
15 | - [Linux (66 MB)](https://github.com/mantreshkhurana/ChatGPT-electron/releases/download/1.0.0/ChatGPT-v1.0.0-linux.tar.xz)
16 |
17 | ## Releases
18 |
19 | - [Latest Release](https://github.com/mantreshkhurana/ChatGPT-electron/releases)
20 |
21 | ## Installation
22 |
23 | ```bash
24 | git clone https://github.com/mantreshkhurana/ChatGPT-electron.git
25 | cd ChatGPT-electron
26 | npm install
27 | ```
28 |
29 | ## Run
30 |
31 | ```bash
32 | npm start
33 | ```
34 |
35 | ## Build
36 |
37 | Binary files for Windows, Linux and Mac are available in the `release-builds/` folder.
38 |
39 | ### For Windows
40 |
41 | ```bash
42 | npm run package-win
43 | ```
44 |
45 | ### For Linux
46 |
47 | ```bash
48 | npm run package-linux
49 | ```
50 |
51 | ### For Mac
52 |
53 | ```bash
54 | npm run package-mac
55 | ```
56 |
57 | ## Credits
58 |
59 | - [OpenAI](https://openai.com/)
60 |
61 | ## Author
62 |
63 | - [Mantresh Khurana](https://github.com/mantreshkhurana)
64 |
--------------------------------------------------------------------------------
/src/menu.js:
--------------------------------------------------------------------------------
1 | exports.createTemplate = (name) => {
2 | let template = [
3 | {
4 | label: "Edit",
5 | submenu: [
6 | { role: "undo" },
7 | { role: "redo" },
8 | { type: "separator" },
9 | { role: "cut" },
10 | { role: "copy" },
11 | { role: "paste" },
12 | { role: "pasteandmatchstyle" },
13 | { role: "delete" },
14 | { role: "selectall" },
15 | ],
16 | },
17 | {
18 | label: "View",
19 | submenu: [
20 | { role: "reload" },
21 | { role: "forcereload" },
22 | { role: "toggledevtools" },
23 | { type: "separator" },
24 | { role: "resetzoom" },
25 | { role: "zoomin" },
26 | { role: "zoomout" },
27 | { type: "separator" },
28 | { role: "togglefullscreen" },
29 | ],
30 | },
31 | {
32 | role: "window",
33 | submenu: [{ role: "minimize" }, { role: "close" }],
34 | },
35 | ];
36 |
37 | if (process.platform === "darwin") {
38 | template.unshift({
39 | label: name,
40 | submenu: [
41 | { type: "separator" },
42 | { role: "services", submenu: [] },
43 | { type: "separator" },
44 | { role: "hide" },
45 | { role: "hideothers" },
46 | { role: "unhide" },
47 | { type: "separator" },
48 | { role: "quit" },
49 | ],
50 | });
51 |
52 | template[1].submenu.push(
53 | { type: "separator" },
54 | {
55 | label: "Speech",
56 | submenu: [{ role: "startspeaking" }, { role: "stopspeaking" }],
57 | }
58 | );
59 |
60 | template[3].submenu = [
61 | { role: "close" },
62 | { role: "minimize" },
63 | { role: "zoom" },
64 | { type: "separator" },
65 | { role: "front" },
66 | ];
67 | }
68 |
69 | return template;
70 | };
71 |
--------------------------------------------------------------------------------