Skip to content

Commit

Permalink
chatgpt working fully but for gmail only
Browse files Browse the repository at this point in the history
  • Loading branch information
sahil-lalani committed Aug 14, 2024
1 parent 4f30c61 commit 71010c5
Show file tree
Hide file tree
Showing 9 changed files with 144 additions and 60 deletions.
54 changes: 48 additions & 6 deletions src/main/Companies/OpenAI/chatgpt.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,56 @@ async function exportChatgpt(company, runID) {
confirmExport.click();

// TODO: automatically go to user's email and download the file
await wait(3)
bigStepper(runID)
ipcRenderer.sendToHost('change-url', 'https://gmail.com', runID) // later this will not be hardcoded
}

async function continueExportChatgpt(id){
// Check for the email every second
if (document.querySelector('h1')) {
ipcRenderer.send('connect-website', company);
return;
}

let emailFound = false;
const checkEmails = async () => {
const emails = await waitForElement("div.xS[role='link']", 'Download Email', true);
for (const email of emails) {
if (email.innerText.includes('ChatGPT - Your data export is ready')) {
bigStepper(id)
email.click();
emailFound = true;
break;
}
}
};

// ipcRenderer.sendToHost('new-url', 'https://gmail.com')
while (!emailFound) {
await checkEmails();
if (!emailFound) {
await wait(1); // Wait for 1 second before checking again
}
}

// ipcRenderer.on('new-url-success', (event, url) => {
// customConsoleLog('New URL:', url);
// // execute clicking the email + downloading!
// });
// Wait for the email to load
await wait(2);

let downloadBtns = [];
while (downloadBtns.length === 0) {
downloadBtns = await waitForElement(
'a[href*="https://proddatamgmtqueue.blob.core.windows.net/exportcontainer/"]',
'Download button',
true
);
if (downloadBtns.length === 0) {
await wait(1); // Wait for 1 second before checking again
}
}
customConsoleLog('downloadBtns: ', downloadBtns);
bigStepper(id)
downloadBtns[downloadBtns.length - 1].click();

}

module.exports = exportChatgpt;
module.exports = { exportChatgpt, continueExportChatgpt };
4 changes: 3 additions & 1 deletion src/main/Companies/OpenAI/chatgpt.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The `exportChatgpt()` function performs these tasks:
1. Checks if the user is connected to ChatGPT.
2. Navigates through the ChatGPT interface to reach the export dialog.
3. Initiates the export of all conversation history.
4. Goes to gmail and downloads the exported file.

## Implementation

Expand All @@ -22,10 +23,11 @@ The ChatGPT export process is integrated into the main application via `preloadW
1. DOM Manipulation: The module relies on specific element attributes and text content to navigate the ChatGPT interface.
2. Timing: Fixed timeouts are used to account for page load times.
3. Element Visibility: The function waits for specific elements to appear before interacting with them.
4. Dynamic Download: The function goes to gmail and downloads the exported file.

## Future Improvements

1. Error Handling: Implement more robust error handling for each step of the process.
2. Dynamic Waiting: Replace fixed timeouts with dynamic waiting for elements to appear.
3. Automatic Download: Implement automatic access to the user's email to download the exported file.
3. Dynamic Download: While this works on gmail, not every user has a gmail account. Thus, other platforms need to be handled.
4. Progress Tracking: Implement a way to track and report the export progress.
46 changes: 29 additions & 17 deletions src/main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ export const createWindow = async (visible: boolean = true) => {
details.url.includes('about:blank') ||
details.url.includes('file://') ||
details.url.includes('https://www.notion.so/verifyNoPopupBlocker') ||
details.url.includes('https://appleid.apple.com/auth/')
details.url.includes('https://appleid.apple.com/auth/') ||
details.url.includes('https://proddatamgmtqueue.blob.core.windows.net/exportcontainer/')
) {
console.log('ALLOWING THIS URL: ', details.url);
return { action: 'allow' };
Expand Down Expand Up @@ -217,7 +218,7 @@ export const createWindow = async (visible: boolean = true) => {
if (process.env.START_MINIMIZED) {
mainWindow.minimize();
} else {
mainWindow.show();
mainWindow.show();
}
});

Expand Down Expand Up @@ -316,21 +317,35 @@ export const createWindow = async (visible: boolean = true) => {

const userData = app.getPath('userData');
const surferDataPath = path.join(userData, 'surfer_data');
let platformPath;
let companyPath: string;
let platformPath: string;

if (url.includes('file.notion.so')) {
platformPath = path.join(surferDataPath, 'Notion');
companyPath = path.join(surferDataPath, 'Notion');
platformPath = path.join(companyPath, 'Notion');
} else if (url.includes('proddatamgmtqueue.blob.core.windows.net/exportcontainer/')) {
companyPath = path.join(surferDataPath, 'OpenAI');
platformPath = path.join(companyPath, 'ChatGPT');
} else {
console.error('Unknown download URL:', url);
return;
}

// Create surfer_data folder if it doesn't exist
if (!fs.existsSync(surferDataPath)) {
fs.mkdirSync(surferDataPath);
}
// Create platform_name folder if it doesn't exist, and clear it if it does

// Create company folder if it doesn't exist
if (!fs.existsSync(companyPath)) {
fs.mkdirSync(companyPath);
}

// Create or clear platform_name folder
if (!fs.existsSync(platformPath)) {
fs.mkdirSync(platformPath);
} else {
fs.readdirSync(platformPath).forEach((file) => {
fs.readdirSync(platformPath).forEach((file: string) => {
const filePath = path.join(platformPath, file);
if (fs.lstatSync(filePath).isDirectory()) {
fs.rmSync(filePath, { recursive: true });
Expand All @@ -340,26 +355,24 @@ export const createWindow = async (visible: boolean = true) => {
});
}

// Create a workspace-specific folder within the downloads directory

event.preventDefault();

console.log('Starting download:', url);

download(mainWindow, url, {
directory: platformPath,
filename: fileName,
onStarted: (downloadItem) => {
onStarted: (downloadItem: Electron.DownloadItem) => {
console.log('Download started:', url);
downloadItem.on('done', (event, state) => {
downloadItem.on('done', (event: Electron.Event, state: string) => {
if (state === 'completed') {
console.log('Download completed successfully:', url);
} else if (state === 'cancelled') {
console.log('Download was cancelled:', url);
}
});
},
onProgress: (percent) => {
onProgress: (percent: number) => {
console.log(`Download progress for ${url}: ${percent}%`);
mainWindow?.webContents.send('download-progress', {
fileName,
Expand All @@ -368,7 +381,7 @@ export const createWindow = async (visible: boolean = true) => {
},
saveAs: false,
})
.then((dl) => {
.then((dl: Electron.DownloadItem) => {
console.log('Download completed:', dl.getSavePath());
const filePath = dl.getSavePath();

Expand All @@ -380,15 +393,15 @@ export const createWindow = async (visible: boolean = true) => {

fs.unlinkSync(filePath);
console.log('Original zip file removed:', filePath);
mainWindow?.webContents.send('export-complete', 'Notion', 'Notion', 0, platformPath);
mainWindow?.webContents.send('export-complete', path.basename(companyPath), path.basename(platformPath), 0, platformPath);
mainWindow?.webContents.send('download-complete', {
fileName,
filePath: platformPath,
fileSize,
extracted: true,
});
})
.catch((error) => {
.catch((error: Error) => {
console.error('Error extracting zip file:', error);
mainWindow?.webContents.send('download-error', {
fileName,
Expand All @@ -405,7 +418,7 @@ export const createWindow = async (visible: boolean = true) => {
});
}
})
.catch((error) => {
.catch((error: Error) => {
console.error('Download failed:', error);
console.error('Error stack:', error.stack);
mainWindow?.webContents.send('download-error', {
Expand All @@ -414,8 +427,7 @@ export const createWindow = async (visible: boolean = true) => {
});
});
});

};
}


ipcMain.on('open-external', (event, url) => {
Expand Down
10 changes: 8 additions & 2 deletions src/main/preloadWebview.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const exportTwitter = require('./Companies/X Corp/twitter');
const electronHandler = require('./preloadElectron');
const exportGmail = require('./Companies/Google/gmail');
const exportYouTube = require('./Companies/Google/youtube');
const exportChatgpt = require('./Companies/OpenAI/chatgpt');
const { exportChatgpt, continueExportChatgpt } = require('./Companies/OpenAI/chatgpt');
contextBridge.exposeInMainWorld('electron', electronHandler);

ipcRenderer.on('export-website', async (event, company, name, runID) => {
Expand All @@ -44,7 +44,7 @@ ipcRenderer.on('export-website', async (event, company, name, runID) => {
await exportYouTube(company, name, runID);
break;
case 'ChatGPT':
await exportChatgpt(company, name, runID);
await exportChatgpt(company, runID);
break;
}
});
Expand All @@ -54,3 +54,9 @@ ipcRenderer.on('export-website', async (event, company, name, runID) => {
await continueExportGithub();
}
})();

ipcRenderer.on('change-url-success', async (event, url, id) => {
if (id.includes('chatgpt-001')) {
await continueExportChatgpt(id);
}
})
22 changes: 12 additions & 10 deletions src/renderer/components/profile/DataExtractionTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { Checkbox } from "../ui/checkbox";
import { formatDistanceToNow, parseISO } from 'date-fns';
import { Progress } from "../ui/progress";
import RunDetailsPage from './RunDetailsPage';
import { platform } from 'os';

const DataExtractionTable = ({ onPlatformClick, webviewRef }) => {
const dispatch = useDispatch();
Expand Down Expand Up @@ -68,19 +69,18 @@ const DataExtractionTable = ({ onPlatformClick, webviewRef }) => {
// }, [])

useEffect(() => {
const handleExportComplete = (platformId, name, runID, namePath) => {
const handleExportComplete = (company, name, runID, namePath) => {

if (name === 'Notion') {
console.log('stopping notion run: ', runs)
// change this to .filter or smth else later to account for multiple notion runs
const notionRun = runs.filter(run => run.platformId === 'notion-001')[0];

dispatch(updateExportStatus(platformId, name, notionRun.id, namePath));
if (runID === 0) {
console.log('stopping download run: ', runs)
const downloadRun = runs.filter(run => run.platformId === `${name.toLowerCase()}-001`)[0];
// change this to .filter or smth else later to account for multiple download runs
dispatch(updateExportStatus(company, name, downloadRun.id, namePath));
}

else {
console.log('stopping run for platform id: ', platformId, ', and name: ', name, ', and runID: ', runID)
dispatch(updateExportStatus(platformId, name, runID, namePath));
console.log('stopping run for platform id: ', company, name, ', and runID: ', runID)
dispatch(updateExportStatus(company, name, runID, namePath));

}

Expand Down Expand Up @@ -123,7 +123,9 @@ const DataExtractionTable = ({ onPlatformClick, webviewRef }) => {
);
};

const filteredPlatforms = platforms.filter(platform =>
const filteredPlatforms = platforms
.filter(platform => platform.steps)
.filter(platform =>
platform.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
platform.company.toLowerCase().includes(searchTerm.toLowerCase())
);
Expand Down
16 changes: 11 additions & 5 deletions src/renderer/components/profile/WebviewManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useSelector, useDispatch } from 'react-redux';
import styled from 'styled-components';
import { ChevronLeft, ChevronRight, X, Square, Bug } from 'lucide-react';
import { IAppState } from '../../types/interfaces';
import { setActiveRunIndex, closeRun, toggleRunVisibility, stopRun, adjustActiveRunIndex, updateExportStatus } from '../../state/actions';
import { setActiveRunIndex, closeRun, toggleRunVisibility, stopRun, adjustActiveRunIndex, updateRunURL } from '../../state/actions';
import { platforms } from '../../config/platforms';
import { useTheme } from '../ui/theme-provider';
import { openDB } from 'idb'; // Import openDB for IndexedDB operations
Expand Down Expand Up @@ -199,11 +199,17 @@ const WebviewManager: React.FC<WebviewManagerProps> = ({ webviewRef, isConnected
// UPDATE IN REDUX HERE!
}

if (channel === 'new-url') {
console.log('new url: ', args[0])
webview.src = args[0];
if (channel === 'change-url') {
const url = args[0]
const id = args[1]
console.log('this runs: ', runs)
console.log('this url: ', url)
console.log('this id: ', id)
const run = runs.find(run => run.id === id)
console.log('this run: ', run)
dispatch(updateRunURL(id, url));
await new Promise((resolve) => setTimeout(resolve, 2000))
webview.send('new-url-success')
webview.send('change-url-success', url, id)
}
};

Expand Down
5 changes: 4 additions & 1 deletion src/renderer/config/platforms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ export const platforms: IPlatform[] = [
light: ChatGPTLight,
dark: ChatGPTDark,
},
company: 'Open AI',
company: 'OpenAI',
companyLogo: '/assets/logos/openai.png',
home_url: 'https://chatgpt.com/#settings/DataControls',
subRuns: [],
Expand All @@ -474,6 +474,9 @@ export const platforms: IPlatform[] = [
{ id: 'step-001', name: 'Go to ChatGPT Data Controls', status: 'pending' },
{ id: 'step-002', name: 'Click on Export', status: 'pending' },
{ id: 'step-003', name: 'Click on Confirm Export', status: 'pending' },
{ id: 'step-004', name: 'Go to Gmail and wait for export email', status: 'pending' },
{ id: 'step-005', name: 'Click on export email', status: 'pending' },
{ id: 'step-007', name: 'Download export', status: 'pending' },
],
},
{
Expand Down
9 changes: 7 additions & 2 deletions src/renderer/state/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,9 @@ export const stopRun = (runId: string) => ({
payload: runId,
});

export const updateExportStatus = (platformId: string, name: string, runID: string, exportPath: string) => ({
export const updateExportStatus = (company: string, name: string, runID: string, exportPath: string) => ({
type: 'UPDATE_EXPORT_STATUS',
payload: { platformId, name, runID, exportPath },
payload: { company, name, runID, exportPath },
});

export const setExportRunning = (platformId: string, isRunning: boolean) => ({
Expand Down Expand Up @@ -148,3 +148,8 @@ export const updateBreadcrumbToIndex = (index: number) => ({
export const stopAllJobs = () => ({
type: 'STOP_ALL_JOBS',
});

export const updateRunURL = (runId: string, newUrl: string) => ({
type: 'UPDATE_RUN_URL',
payload: { runId, newUrl }
});
Loading

0 comments on commit 71010c5

Please sign in to comment.