Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
# CodeInterviewAssist

> ## ⚠️ IMPORTANT NOTICE TO THE COMMUNITY ⚠️
>
>
> **This is a free, open-source initiative - NOT a full-service product!**
>
>
> There are numerous paid interview preparation tools charging hundreds of dollars for comprehensive features like live audio capture, automated answer generation, and more. This project is fundamentally different:
>
>
> - This is a **small, non-profit, community-driven project** with zero financial incentive behind it
> - The entire codebase is freely available for anyone to use, modify, or extend
> - Want features like voice support? You're welcome to integrate tools like OpenAI's Whisper or other APIs
> - New features should come through **community contributions** - it's unreasonable to expect a single maintainer to implement premium features for free
> - The maintainer receives no portfolio benefit, monetary compensation, or recognition for this work
>
>
> **Before submitting feature requests or expecting personalized support, please understand this project exists purely as a community resource.** If you value what's been created, the best way to show appreciation is by contributing code, documentation, or helping other users.

> ## 🔑 API KEY INFORMATION - UPDATED
Expand Down Expand Up @@ -44,7 +44,7 @@ The codebase is designed to be adaptable:

- **AI Models**: Though currently using OpenAI's models, you can modify the code to integrate with other providers like Claude, Deepseek, Llama, or any model with an API. All integration code is in `electron/ProcessingHelper.ts` and UI settings are in `src/components/Settings/SettingsDialog.tsx`.
- **Languages**: Add support for additional programming languages
- **Features**: Extend the functionality with new capabilities
- **Features**: Extend the functionality with new capabilities
- **UI**: Customize the interface to your preferences

All it takes is modest JavaScript/TypeScript knowledge and understanding of the API you want to integrate.
Expand Down Expand Up @@ -248,13 +248,15 @@ The packaged applications will be available in the `release` directory.
- Window remains invisible to specified screen sharing applications
- Start a new problem using [Control or Cmd + R]

6. **Language Selection
6. **Language Selection**

- Easily switch between programming languages with a single click
- Use arrow keys for keyboard navigation through available languages
- The system dynamically adapts to any languages added or removed from the codebase
- Your language preference is saved between sessions

> Note: The Application logs can take a lot of space after prolonged usage, to deal with this we have set a threshold limit of **1GB** on the log files, after that it will be deleted automatically. Location of the log files are mentioned within the application for easy debugging when encountering a bug.

## Adding More AI Models

This application is built with extensibility in mind. You can easily add support for additional LLMs alongside the existing OpenAI integration:
Expand Down
139 changes: 139 additions & 0 deletions electron/SafeLogger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import fs from 'fs'
import path from 'path'
import { app } from 'electron'

class SafeLogger {
private logDir: string
private mainLogPath: string
private shortcutLogPath: string

constructor() {
// Initialize log directory
this.logDir = path.join(app.getPath('userData'), 'logs')
this.mainLogPath = path.join(this.logDir, 'main-events.log')
this.shortcutLogPath = path.join(this.logDir, 'shortcut-events.log')

// Create logs directory if it doesn't exist
this.ensureLogDirectory()
}

private ensureLogDirectory(): void {
try {
if (!fs.existsSync(this.logDir)) {
fs.mkdirSync(this.logDir, { recursive: true })
}
} catch (error) {
// Silently fail - we can't log the error since we're creating the logger
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should silently fail this - if this fails there is no way of figuring out what went wrong before or after

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're absolutely right. If the log directory creation fails, we should at least attempt to use a fallback location or provide some indication of the failure. I'll update this to try a fallback directory and use stderr as a last resort.

}
}

private formatLogMessage(level: string, source: string, ...args: any[]): string {
const timestamp = new Date().toISOString()
const message = args.map(arg =>
typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)
).join(' ')
return `[${timestamp}] [${level}] [${source}] ${message}\n`
}

private writeToFile(filePath: string, message: string): void {
try {
// Check size limit before writing
this.checkAndClearIfOverLimit()
fs.appendFileSync(filePath, message, 'utf8')
} catch (error) {
// Silently fail - we can't use console.log here as it would cause the same issue
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This silent failing is fine as everything would be in the log file already.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, this silent failing is appropriate here since if we can't write to the log file, using console.log would defeat the purpose and potentially cause the original EIO error we're trying to solve.

}
}

// Main process logging
mainLog(...args: any[]): void {
const message = this.formatLogMessage('INFO', 'MAIN', ...args)
this.writeToFile(this.mainLogPath, message)
}

mainError(...args: any[]): void {
const message = this.formatLogMessage('ERROR', 'MAIN', ...args)
this.writeToFile(this.mainLogPath, message)
}

mainWarn(...args: any[]): void {
const message = this.formatLogMessage('WARN', 'MAIN', ...args)
this.writeToFile(this.mainLogPath, message)
}

// Shortcut process logging
shortcutLog(...args: any[]): void {
const message = this.formatLogMessage('INFO', 'SHORTCUT', ...args)
this.writeToFile(this.shortcutLogPath, message)
}

shortcutError(...args: any[]): void {
const message = this.formatLogMessage('ERROR', 'SHORTCUT', ...args)
this.writeToFile(this.shortcutLogPath, message)
}

shortcutWarn(...args: any[]): void {
const message = this.formatLogMessage('WARN', 'SHORTCUT', ...args)
this.writeToFile(this.shortcutLogPath, message)
}

// Generic logging method
log(source: string, level: 'INFO' | 'ERROR' | 'WARN', ...args: any[]): void {
const logPath = source === 'SHORTCUT' ? this.shortcutLogPath : this.mainLogPath
const message = this.formatLogMessage(level, source, ...args)
this.writeToFile(logPath, message)
}

// Check total log directory size
private getDirectorySize(): number {
try {
let totalSize = 0
const files = fs.readdirSync(this.logDir)

files.forEach(file => {
const filePath = path.join(this.logDir, file)
const stats = fs.statSync(filePath)
totalSize += stats.size
})

return totalSize
} catch (error) {
return 0
}
}

// Clear all logs if size exceeds 1GB
private checkAndClearIfOverLimit(): void {
try {
const sizeLimit = 1024 * 1024 * 1024 // 1GB in bytes
const currentSize = this.getDirectorySize()

if (currentSize > sizeLimit) {
// Clear all log files
const files = fs.readdirSync(this.logDir)
files.forEach(file => {
const filePath = path.join(this.logDir, file)
try {
fs.unlinkSync(filePath)
} catch (error) {
// Silently fail for individual file deletion
}
})

// Log the cleanup action
const message = this.formatLogMessage('INFO', 'SYSTEM', `Log directory cleared due to size limit (${(currentSize / 1024 / 1024).toFixed(2)}MB exceeded 1GB limit)`)
this.writeToFile(this.mainLogPath, message)
}
} catch (error) {
// Silently fail
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be logged normally

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, since this would be called during normal operation (not during logger initialization), we can safely log this error using our own logging methods.

}
}
}

// Create singleton instance
export const safeLogger = new SafeLogger()

// Convenience functions for backward compatibility
export const safeLog = (...args: any[]) => safeLogger.mainLog(...args)
export const safeError = (...args: any[]) => safeLogger.mainError(...args)
export const safeWarn = (...args: any[]) => safeLogger.mainWarn(...args)
Loading