104 lines
4.2 KiB
JavaScript
104 lines
4.2 KiB
JavaScript
import { app, BrowserWindow, ipcMain } from 'electron';
|
|
import path from 'path';
|
|
import url from 'url';
|
|
import { fileURLToPath } from 'url';
|
|
|
|
// Keep an in-memory API key for the running session only. Renderer should still store key in localStorage.
|
|
let inMemoryKey = null;
|
|
|
|
function createWindow() {
|
|
// Resolve dirname equivalent in ESM
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
const win = new BrowserWindow({
|
|
width: 1200,
|
|
height: 800,
|
|
webPreferences: {
|
|
// Preload is colocated with the electron main files after the refactor
|
|
preload: path.join(__dirname, 'electron-preload.js'),
|
|
contextIsolation: true,
|
|
nodeIntegration: false,
|
|
}
|
|
});
|
|
|
|
const startUrl = process.env.ELECTRON_START_URL || url.pathToFileURL(path.join(process.cwd(), 'dist', 'index.html')).toString();
|
|
win.loadURL(startUrl).catch(err => {
|
|
console.error('[electron-main] Failed to load URL:', err);
|
|
});
|
|
|
|
if (process.env.ELECTRON_START_URL) {
|
|
try {
|
|
const ses = win.webContents.session;
|
|
ses.webRequest.onHeadersReceived((details, callback) => {
|
|
const headers = details.responseHeaders || {};
|
|
// Allow jsDelivr CDN for scripts used by third-party libs (dev only)
|
|
// Dev CSP: allow inline scripts, unsafe-eval and jsDelivr CDN for third-party libs (HMR and wasm loaders need inline scripts/eval)
|
|
headers['Content-Security-Policy'] = [
|
|
"default-src 'self' 'unsafe-eval' 'unsafe-inline' data:; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net; img-src 'self' data:; connect-src *; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' data: https://fonts.gstatic.com"
|
|
];
|
|
callback({ responseHeaders: headers });
|
|
});
|
|
} catch (e) {
|
|
console.warn('[electron-main] Failed to inject dev CSP:', e);
|
|
}
|
|
win.webContents.once('did-frame-finish-load', () => {
|
|
try {
|
|
win.webContents.openDevTools({ mode: 'right' });
|
|
} catch (e) {
|
|
console.warn('[electron-main] Could not open DevTools:', e);
|
|
}
|
|
});
|
|
}
|
|
|
|
win.webContents.on('did-finish-load', () => {
|
|
console.log('[electron-main] Renderer finished load; title=', win.getTitle());
|
|
});
|
|
}
|
|
|
|
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();
|
|
});
|
|
|
|
ipcMain.handle('generate-avatar', async (event, prompt) => {
|
|
try {
|
|
console.log('[electron-main] generate-avatar handler invoked');
|
|
console.log('[electron-main] prompt length:', (prompt || '').length);
|
|
|
|
// Prefer an in-memory key, then environment variables
|
|
const apiKey = inMemoryKey || process.env.GEMINI_API_KEY || process.env.API_KEY;
|
|
console.log('[electron-main] apiKey present?', !!apiKey, '(will prefer GEMINI_API_KEY if set)');
|
|
|
|
if (apiKey) {
|
|
try {
|
|
console.log('[electron-main] Calling GenAI helper...');
|
|
const imageData = await generateAvatarWithGenAI(prompt || '', apiKey);
|
|
console.log('[electron-main] GenAI helper returned image, length:', imageData?.length || 0);
|
|
return { image: imageData };
|
|
} catch (e) {
|
|
console.error('[electron-main] GenAI generation failed:', e?.message || e);
|
|
}
|
|
} else {
|
|
console.log('[electron-main] No API key present — skipping GenAI call and returning placeholder');
|
|
}
|
|
} catch (outerErr) {
|
|
console.error('[electron-main] Unexpected error in generate-avatar handler:', outerErr);
|
|
}
|
|
|
|
// Fallback placeholder image
|
|
const placeholder = `data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='1400' height='900'><rect width='100%' height='100%' fill='%230f172a' /><text x='50%' y='50%' fill='white' font-size='40' font-family='Inter' dominant-baseline='middle' text-anchor='middle'>Placeholder: ${encodeURIComponent((prompt||'').substring(0,80))}</text></svg>`;
|
|
console.log('[electron-main] Returning placeholder image (length):', placeholder.length);
|
|
return { image: placeholder };
|
|
});
|
|
|
|
// Expose simple key management for the renderer via ipc (session-only)
|
|
// No renderer-side key persistence — frontend uses localStorage exclusively now.
|