diff --git a/electron/ConfigHelper.ts b/electron/ConfigHelper.ts index 6d1d2db..240fd1a 100644 --- a/electron/ConfigHelper.ts +++ b/electron/ConfigHelper.ts @@ -328,20 +328,16 @@ export class ConfigHelper extends EventEmitter { } catch (error: any) { console.error('OpenAI API key test failed:', error); - // Determine the specific error type for better error messages - let errorMessage = 'Unknown error validating OpenAI API key'; - + // Return error without showing dialog if (error.status === 401) { - errorMessage = 'Invalid API key. Please check your OpenAI key and try again.'; + return { valid: false, error: 'Invalid API key' }; } else if (error.status === 429) { - errorMessage = 'Rate limit exceeded. Your OpenAI API key has reached its request limit or has insufficient quota.'; + return { valid: false, error: 'Rate limit exceeded' }; } else if (error.status === 500) { - errorMessage = 'OpenAI server error. Please try again later.'; - } else if (error.message) { - errorMessage = `Error: ${error.message}`; + return { valid: false, error: 'OpenAI server error' }; + } else { + return { valid: false, error: error.message || 'Unknown error' }; } - - return { valid: false, error: errorMessage }; } } diff --git a/electron/ProcessingHelper.ts b/electron/ProcessingHelper.ts index 0dcd26f..77ee22a 100644 --- a/electron/ProcessingHelper.ts +++ b/electron/ProcessingHelper.ts @@ -188,11 +188,11 @@ export class ProcessingHelper { } } - // Default fallback - return "python"; + // Default to auto instead of python + return "auto"; } catch (error) { console.error("Error getting language:", error) - return "python" + return "auto" } } @@ -346,7 +346,6 @@ export class ProcessingHelper { if (!extraScreenshotQueue || extraScreenshotQueue.length === 0) { console.log("No extra screenshots found in queue"); mainWindow.webContents.send(this.deps.PROCESSING_EVENTS.NO_SCREENSHOTS); - return; } @@ -443,48 +442,47 @@ export class ProcessingHelper { signal: AbortSignal ) { try { - const config = configHelper.loadConfig(); const language = await this.getLanguage(); + const config = configHelper.loadConfig(); const mainWindow = this.deps.getMainWindow(); - // Step 1: Extract problem info using AI Vision API (OpenAI or Gemini) - const imageDataList = screenshots.map(screenshot => screenshot.data); - - // Update the user on progress + // Create base64 image data array + const imageDataList = screenshots.map(s => s.data); + if (mainWindow) { mainWindow.webContents.send("processing-status", { - message: "Analyzing problem from screenshots...", - progress: 20 + message: "Analyzing screenshots...", + progress: 30 }); } - let problemInfo; + let responseContent; if (config.apiProvider === "openai") { - // Verify OpenAI client + // OpenAI processing if (!this.openaiClient) { - this.initializeAIClient(); // Try to reinitialize - - if (!this.openaiClient) { - return { - success: false, - error: "OpenAI API key not configured or invalid. Please check your settings." - }; - } + return { + success: false, + error: "OpenAI API key not configured. Please check your settings." + }; } - // Use OpenAI for processing + // Create OpenAI message structure const messages = [ { - role: "system" as const, - content: "You are a coding challenge interpreter. Analyze the screenshot of the coding problem and extract all relevant information. Return the information in JSON format with these fields: problem_statement, constraints, example_input, example_output. Just return the structured JSON without any other text." + role: "system" as const, + content: language === 'auto' ? + "You are a coding challenge interpreter. Analyze the screenshots of the coding problem, identify the programming language being used, and extract all relevant information. Return the information in JSON format with these fields: problem_statement (which must include the identified programming language), constraints, example_input, example_output. Just return the structured JSON without any other text." : + "You are a coding challenge interpreter. Analyze the screenshots of the coding problem and extract all relevant information. Return the information in JSON format with these fields: problem_statement, constraints, example_input, example_output. Just return the structured JSON without any other text." }, { role: "user" as const, content: [ { - type: "text" as const, - text: `Extract the coding problem details from these screenshots. Return in JSON format. Preferred coding language we gonna use for this problem is ${language}.` + type: "text" as const, + text: language === 'auto' ? + "Analyze the screenshots, identify the programming language being used or required, and extract all relevant information. Make sure to include the identified programming language in the problem statement." : + `Preferred coding language we gonna use for this problem is ${language}.` }, ...imageDataList.map(data => ({ type: "image_url" as const, @@ -507,7 +505,7 @@ export class ProcessingHelper { const responseText = extractionResponse.choices[0].message.content; // Handle when OpenAI might wrap the JSON in markdown code blocks const jsonText = responseText.replace(/```json|```/g, '').trim(); - problemInfo = JSON.parse(jsonText); + responseContent = JSON.parse(jsonText); } catch (error) { console.error("Error parsing OpenAI response:", error); return { @@ -531,7 +529,9 @@ export class ProcessingHelper { role: "user", parts: [ { - text: `You are a coding challenge interpreter. Analyze the screenshots of the coding problem and extract all relevant information. Return the information in JSON format with these fields: problem_statement, constraints, example_input, example_output. Just return the structured JSON without any other text. Preferred coding language we gonna use for this problem is ${language}.` + text: language === 'auto' ? + "You are a coding challenge interpreter. Analyze the screenshots of the coding problem, identify the programming language being used, and extract all relevant information. Return the information in JSON format with these fields: problem_statement (which must include the identified programming language), constraints, example_input, example_output. Just return the structured JSON without any other text." : + `You are a coding challenge interpreter. Analyze the screenshots of the coding problem and extract all relevant information. Return the information in JSON format with these fields: problem_statement, constraints, example_input, example_output. Just return the structured JSON without any other text. Preferred coding language we gonna use for this problem is ${language}.` }, ...imageDataList.map(data => ({ inlineData: { @@ -566,7 +566,7 @@ export class ProcessingHelper { // Handle when Gemini might wrap the JSON in markdown code blocks const jsonText = responseText.replace(/```json|```/g, '').trim(); - problemInfo = JSON.parse(jsonText); + responseContent = JSON.parse(jsonText); } catch (error) { console.error("Error using Gemini API:", error); return { @@ -645,13 +645,13 @@ export class ProcessingHelper { } // Store problem info in AppState - this.deps.setProblemInfo(problemInfo); + this.deps.setProblemInfo(responseContent); // Send first success event if (mainWindow) { mainWindow.webContents.send( this.deps.PROCESSING_EVENTS.PROBLEM_EXTRACTED, - problemInfo + responseContent ); // Generate solutions after successful extraction @@ -734,7 +734,31 @@ export class ProcessingHelper { } // Create prompt for solution generation - const promptText = ` + const promptText = language === 'auto' ? ` +Generate a detailed solution for the following coding problem. First analyze the problem statement, constraints, and examples to identify the most appropriate programming language, then provide the solution in that language: + +PROBLEM STATEMENT: +${problemInfo.problem_statement} + +CONSTRAINTS: +${problemInfo.constraints || "No specific constraints provided."} + +EXAMPLE INPUT: +${problemInfo.example_input || "No example input provided."} + +EXAMPLE OUTPUT: +${problemInfo.example_output || "No example output provided."} + +I need the response in the following format: +1. Code: A clean, optimized implementation in the most appropriate programming language (based on the problem and examples) +2. Your Thoughts: A list of key insights and reasoning behind your approach +3. Time complexity: O(X) with a detailed explanation (at least 2 sentences) +4. Space complexity: O(X) with a detailed explanation (at least 2 sentences) + +For complexity explanations, please be thorough. For example: "Time complexity: O(n) because we iterate through the array only once. This is optimal as we need to examine each element at least once to find the solution." or "Space complexity: O(n) because in the worst case, we store all elements in the hashmap. The additional space scales linearly with the input size." + +Your solution should be efficient, well-commented, and handle edge cases. +` : ` Generate a detailed solution for the following coding problem: PROBLEM STATEMENT: @@ -1020,7 +1044,27 @@ Your solution should be efficient, well-commented, and handle edge cases. const messages = [ { role: "system" as const, - content: `You are a coding interview assistant helping debug and improve solutions. Analyze these screenshots which include either error messages, incorrect outputs, or test cases, and provide detailed debugging help. + content: language === 'auto' ? + `You are a coding interview assistant helping debug and improve solutions. Analyze these screenshots which include either error messages, incorrect outputs, or test cases. First identify the programming language from the code, then provide detailed debugging help in that language. + +Your response MUST follow this exact structure with these section headers (use ### for headers): +### Issues Identified +- List each issue as a bullet point with clear explanation + +### Specific Improvements and Corrections +- List specific code changes needed as bullet points + +### Optimizations +- List any performance optimizations if applicable + +### Explanation of Changes Needed +Here provide a clear explanation of why the changes are needed + +### Key Points +- Summary bullet points of the most important takeaways + +If you include code examples, use proper markdown code blocks with the appropriate language specification.` : + `You are a coding interview assistant helping debug and improve solutions. Analyze these screenshots which include either error messages, incorrect outputs, or test cases, and provide detailed debugging help. Your response MUST follow this exact structure with these section headers (use ### for headers): ### Issues Identified @@ -1045,11 +1089,17 @@ If you include code examples, use proper markdown code blocks with language spec content: [ { type: "text" as const, - text: `I'm solving this coding problem: "${problemInfo.problem_statement}" in ${language}. I need help with debugging or improving my solution. Here are screenshots of my code, the errors or test cases. Please provide a detailed analysis with: + text: language === 'auto' ? + `I'm solving this coding problem: "${problemInfo.problem_statement}". Analyze my code to identify the programming language being used, then help me debug or improve my solution. Here are screenshots of my code, the errors or test cases. Please provide a detailed analysis with: +1. What issues you found in my code +2. Specific improvements and corrections +3. Any optimizations that would make the solution better +4. A clear explanation of the changes needed` : + `I'm solving this coding problem: "${problemInfo.problem_statement}" in ${language}. I need help with debugging or improving my solution. Here are screenshots of my code, the errors or test cases. Please provide a detailed analysis with: 1. What issues you found in my code 2. Specific improvements and corrections 3. Any optimizations that would make the solution better -4. A clear explanation of the changes needed` +4. A clear explanation of the changes needed` }, ...imageDataList.map(data => ({ type: "image_url" as const, diff --git a/electron/main.ts b/electron/main.ts index 0eae187..b38047e 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -408,7 +408,7 @@ function showMainWindow(): void { ...state.windowSize }); } - state.mainWindow.setIgnoreMouseEvents(false); + state.mainWindow.setIgnoreMouseEvents(true, { forward: true }); state.mainWindow.setAlwaysOnTop(true, "screen-saver", 1); state.mainWindow.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true diff --git a/src/App.tsx b/src/App.tsx index f2dd348..6eea036 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -89,12 +89,8 @@ function App() { try { const hasKey = await window.electronAPI.checkApiKey() setHasApiKey(hasKey) - - // If no API key is found, show the settings dialog after a short delay if (!hasKey) { - setTimeout(() => { - setIsSettingsOpen(true) - }, 1000) + showToast("API Key Required", "Please set up your API key in settings to use the application.", "neutral") } } catch (error) { console.error("Failed to check API key:", error) @@ -104,7 +100,7 @@ function App() { if (isInitialized) { checkApiKey() } - }, [isInitialized]) + }, [isInitialized, showToast]) // Initialize dropdown handler useEffect(() => { diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index b82b799..f7b1574 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -13,6 +13,8 @@ interface HeaderProps { const LANGUAGES = [ { value: 'python', label: 'Python' }, { value: 'javascript', label: 'JavaScript' }, + { value: 'react', label: 'React.js' }, + { value: 'auto', label: 'Auto (Detect from Screen)' }, { value: 'java', label: 'Java' }, { value: 'cpp', label: 'C++' }, { value: 'csharp', label: 'C#' }, diff --git a/src/components/Settings/SettingsDialog.tsx b/src/components/Settings/SettingsDialog.tsx index 463ea12..0171b4f 100644 --- a/src/components/Settings/SettingsDialog.tsx +++ b/src/components/Settings/SettingsDialog.tsx @@ -293,6 +293,9 @@ export function SettingsDialog({ open: externalOpen, onOpenChange }: SettingsDia window.electronAPI.openLink(url); }; + // Return null if not explicitly opened + if (!open) return null; + return ( { const [updateAvailable, setUpdateAvailable] = useState(false) const [updateDownloaded, setUpdateDownloaded] = useState(false) @@ -13,17 +16,19 @@ export const UpdateNotification: React.FC = () => { console.log("UpdateNotification: Setting up event listeners") const unsubscribeAvailable = window.electronAPI.onUpdateAvailable( - (info) => { + (info: UpdateInfo) => { console.log("UpdateNotification: Update available received", info) setUpdateAvailable(true) + showToast("Update Available", "A new version is available. The app will update on next restart.", "neutral") } ) const unsubscribeDownloaded = window.electronAPI.onUpdateDownloaded( - (info) => { + (info: UpdateInfo) => { console.log("UpdateNotification: Update downloaded received", info) setUpdateDownloaded(true) setIsDownloading(false) + showToast("Update Ready", "Update downloaded. The app will update on next restart.", "neutral") } ) @@ -32,7 +37,7 @@ export const UpdateNotification: React.FC = () => { unsubscribeAvailable() unsubscribeDownloaded() } - }, []) + }, [showToast]) const handleStartUpdate = async () => { console.log("UpdateNotification: Starting update download") @@ -50,52 +55,6 @@ export const UpdateNotification: React.FC = () => { window.electronAPI.installUpdate() } - console.log("UpdateNotification: Render state", { - updateAvailable, - updateDownloaded, - isDownloading - }) - if (!updateAvailable && !updateDownloaded) return null - - return ( - - e.preventDefault()} - > -
-

- {updateDownloaded - ? "Update Ready to Install" - : "A New Version is Available"} -

-

- {updateDownloaded - ? "The update has been downloaded and will be installed when you restart the app." - : "A new version of Interview Coder is available. Please update to continue using the app."} -

-
- {updateDownloaded ? ( - - ) : ( - - )} -
-
-
-
- ) + // Return null to prevent any UI from showing + return null } diff --git a/src/components/shared/LanguageSelector.tsx b/src/components/shared/LanguageSelector.tsx index 2f63f79..914cb0c 100644 --- a/src/components/shared/LanguageSelector.tsx +++ b/src/components/shared/LanguageSelector.tsx @@ -42,6 +42,8 @@ export const LanguageSelector: React.FC = ({ > + +