Skip to content

Commit

Permalink
auto install requirements on startup + python handling
Browse files Browse the repository at this point in the history
  • Loading branch information
sahil-lalani committed Dec 21, 2024
1 parent a3378e4 commit 3574866
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 11 deletions.
1 change: 1 addition & 0 deletions desktop/assets/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
chromadb
54 changes: 50 additions & 4 deletions desktop/src/main/helpers/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { dialog } from 'electron';
import { promisify } from 'util';
import { exec } from 'child_process';
const execAsync = promisify(exec);
import { getAssetPath } from '../main';

export function resolveHtmlPath(htmlFileName: string) {
if (process.env.NODE_ENV === 'development') {
Expand Down Expand Up @@ -74,13 +75,58 @@ export async function checkPythonAvailability(on_startup: boolean = false, actio
title: 'Some features require Python',
message: 'Python is required for iMessage export, local vectorization, and more. Please go to https://www.python.org/downloads/ and install Python 3.10 or later.',
});
}

else {
} else {
await dialog.showMessageBox({
type: 'error',
title: 'Python Required for this action',
message: `Python is required for ${action}. Please go to https://www.python.org/downloads/ and install Python 3.10 or later.`,
});
}
}
return null;
}

export async function checkAndInstallPythonRequirements(): Promise<boolean> {
const pythonCmd = await checkPythonAvailability(true);
if (!pythonCmd) return false;

try {
// First check if pip is installed
await execAsync(`${pythonCmd} -m pip --version`);

// Get the requirements.txt path
const requirementsPath = getAssetPath('requirements.txt');

// Read requirements file
const requirements = fs.readFileSync(requirementsPath, 'utf8').split('\n')
.map(line => line.trim())
.filter(line => line && !line.startsWith('#')); // Remove empty lines and comments

// Check each package
for (const pkg of requirements) {
try {
// Try to import the package using python
await execAsync(`${pythonCmd} -c "import ${pkg.split('==')[0].trim()}"`);
console.log(`Package ${pkg} is already installed`);
} catch (error) {
// Package not found, install it
console.log(`Installing package ${pkg}...`);
const { stdout, stderr } = await execAsync(
`${pythonCmd} -m pip install ${pkg}`
);

console.log('Installation output:', stdout);
if (stderr) console.error('Installation errors:', stderr);
}
}

return true;
} catch (error) {
console.error('Error checking/installing Python requirements:', error);
await dialog.showMessageBox({
type: 'error',
title: 'Error Installing Python Requirements',
message: 'Failed to install required Python packages. Please make sure pip is installed and try again.',
});
return false;
}
}
7 changes: 5 additions & 2 deletions desktop/src/main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { resolveHtmlPath } from './helpers/util';
import { spawn } from 'child_process';
dotenv.config();
const { download } = require('electron-dl');
import { checkPythonAvailability } from './helpers/util';
import { checkPythonAvailability, checkAndInstallPythonRequirements } from './helpers/util';

// Preventing multiple instances of Surfer

Expand Down Expand Up @@ -486,7 +486,7 @@ const RESOURCES_PATH = app.isPackaged
? path.join(process.resourcesPath, 'assets')
: path.join(__dirname, '../../assets');

const getAssetPath = (...paths: string[]): string => {
export const getAssetPath = (...paths: string[]): string => {
return path.join(RESOURCES_PATH, ...paths);
};

Expand Down Expand Up @@ -1334,6 +1334,9 @@ app
}
});
}

// Check and install Python requirements
await checkAndInstallPythonRequirements();
})
.catch(console.log);

Expand Down
4 changes: 2 additions & 2 deletions desktop/src/renderer/components/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { Outlet } from 'react-router-dom';
import { Header } from './Header';
import WebviewManager from './WebviewManager';
import Webview from './Webview';

interface LayoutProps {
webviewRefs: { [key: string]: React.RefObject<HTMLWebViewElement> };
Expand Down Expand Up @@ -33,7 +33,7 @@ const Layout: React.FC<LayoutProps> = ({
>
<div className="absolute inset-0 w-full h-full">
{children}
<WebviewManager
<Webview
webviewRefs={webviewRefs}
getWebviewRef={getWebviewRef}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,14 +126,14 @@ const IconButton = styled.button`
props.disabled ? 'transparent' : '#ffffff1a'};
}
`;
interface WebviewManagerProps {
interface WebviewProps {
webviewRefs: { [key: string]: React.RefObject<HTMLIFrameElement> };
getWebviewRef: (runId: string) => React.RefObject<HTMLIFrameElement>;
}

import { debounce } from 'lodash'; // Make sure to import debounce from lodash

const WebviewManager: React.FC<WebviewManagerProps> = ({
const Webview: React.FC<WebviewProps> = ({
webviewRefs,
getWebviewRef,
}) => {
Expand Down Expand Up @@ -518,4 +518,4 @@ const WebviewManager: React.FC<WebviewManagerProps> = ({
);
};

export default WebviewManager;
export default Webview;

0 comments on commit 3574866

Please sign in to comment.