├── .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 | ![Stars](https://img.shields.io/github/stars/mantreshkhurana/ChatGPT-electron?style=social) 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 | ![Screenshot](https://raw.githubusercontent.com/mantreshkhurana/ChatGPT-electron/stable/screenshots/screenshot-1.png) 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 | --------------------------------------------------------------------------------