Skip to content

Commit 54886cf

Browse files
Devashish NayakDevashish Nayak
authored andcommitted
Added Claude AI
1 parent baeaa1d commit 54886cf

File tree

4 files changed

+385
-25
lines changed

4 files changed

+385
-25
lines changed

electron/ConfigHelper.ts

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { OpenAI } from "openai"
77

88
interface Config {
99
apiKey: string;
10-
apiProvider: "openai" | "gemini"; // Added provider selection
10+
apiProvider: "openai" | "gemini" | "anthropic"; // Added provider selection
1111
extractionModel: string;
1212
solutionModel: string;
1313
debuggingModel: string;
@@ -58,7 +58,7 @@ export class ConfigHelper extends EventEmitter {
5858
/**
5959
* Validate and sanitize model selection to ensure only allowed models are used
6060
*/
61-
private sanitizeModelSelection(model: string, provider: "openai" | "gemini"): string {
61+
private sanitizeModelSelection(model: string, provider: "openai" | "gemini" | "anthropic"): string {
6262
if (provider === "openai") {
6363
// Only allow gpt-4o and gpt-4o-mini for OpenAI
6464
const allowedModels = ['gpt-4o', 'gpt-4o-mini'];
@@ -67,15 +67,25 @@ export class ConfigHelper extends EventEmitter {
6767
return 'gpt-4o';
6868
}
6969
return model;
70-
} else {
70+
} else if (provider === "gemini") {
7171
// Only allow gemini-1.5-pro and gemini-2.0-flash for Gemini
7272
const allowedModels = ['gemini-1.5-pro', 'gemini-2.0-flash'];
7373
if (!allowedModels.includes(model)) {
7474
console.warn(`Invalid Gemini model specified: ${model}. Using default model: gemini-2.0-flash`);
7575
return 'gemini-2.0-flash'; // Changed default to flash
7676
}
7777
return model;
78+
} else if (provider === "anthropic") {
79+
// Only allow Claude models
80+
const allowedModels = ['claude-3-opus-20240229', 'claude-3-sonnet-20240229', 'claude-3-haiku-20240307'];
81+
if (!allowedModels.includes(model)) {
82+
console.warn(`Invalid Anthropic model specified: ${model}. Using default model: claude-3-opus-20240229`);
83+
return 'claude-3-opus-20240229';
84+
}
85+
return model;
7886
}
87+
// Default fallback
88+
return model;
7989
}
8090

8191
public loadConfig(): Config {
@@ -85,7 +95,7 @@ export class ConfigHelper extends EventEmitter {
8595
const config = JSON.parse(configData);
8696

8797
// Ensure apiProvider is a valid value
88-
if (config.apiProvider !== "openai" && config.apiProvider !== "gemini") {
98+
if (config.apiProvider !== "openai" && config.apiProvider !== "gemini" && config.apiProvider !== "anthropic") {
8999
config.apiProvider = "gemini"; // Default to Gemini if invalid
90100
}
91101

@@ -146,6 +156,9 @@ export class ConfigHelper extends EventEmitter {
146156
if (updates.apiKey.trim().startsWith('sk-')) {
147157
provider = "openai";
148158
console.log("Auto-detected OpenAI API key format");
159+
} else if (updates.apiKey.trim().startsWith('sk-ant-')) {
160+
provider = "anthropic";
161+
console.log("Auto-detected Anthropic API key format");
149162
} else {
150163
provider = "gemini";
151164
console.log("Using Gemini API key format (default)");
@@ -161,6 +174,10 @@ export class ConfigHelper extends EventEmitter {
161174
updates.extractionModel = "gpt-4o";
162175
updates.solutionModel = "gpt-4o";
163176
updates.debuggingModel = "gpt-4o";
177+
} else if (updates.apiProvider === "anthropic") {
178+
updates.extractionModel = "claude-3-opus-20240229";
179+
updates.solutionModel = "claude-3-opus-20240229";
180+
updates.debuggingModel = "claude-3-opus-20240229";
164181
} else {
165182
updates.extractionModel = "gemini-2.0-flash";
166183
updates.solutionModel = "gemini-2.0-flash";
@@ -208,11 +225,15 @@ export class ConfigHelper extends EventEmitter {
208225
/**
209226
* Validate the API key format
210227
*/
211-
public isValidApiKeyFormat(apiKey: string, provider?: "openai" | "gemini"): boolean {
228+
public isValidApiKeyFormat(apiKey: string, provider?: "openai" | "gemini" | "anthropic" ): boolean {
212229
// If provider is not specified, attempt to auto-detect
213230
if (!provider) {
214231
if (apiKey.trim().startsWith('sk-')) {
215-
provider = "openai";
232+
if (apiKey.trim().startsWith('sk-ant-')) {
233+
provider = "anthropic";
234+
} else {
235+
provider = "openai";
236+
}
216237
} else {
217238
provider = "gemini";
218239
}
@@ -224,6 +245,9 @@ export class ConfigHelper extends EventEmitter {
224245
} else if (provider === "gemini") {
225246
// Basic format validation for Gemini API keys (usually alphanumeric with no specific prefix)
226247
return apiKey.trim().length >= 10; // Assuming Gemini keys are at least 10 chars
248+
} else if (provider === "anthropic") {
249+
// Basic format validation for Anthropic API keys
250+
return /^sk-ant-[a-zA-Z0-9]{32,}$/.test(apiKey.trim());
227251
}
228252

229253
return false;
@@ -264,12 +288,17 @@ export class ConfigHelper extends EventEmitter {
264288
/**
265289
* Test API key with the selected provider
266290
*/
267-
public async testApiKey(apiKey: string, provider?: "openai" | "gemini"): Promise<{valid: boolean, error?: string}> {
291+
public async testApiKey(apiKey: string, provider?: "openai" | "gemini" | "anthropic"): Promise<{valid: boolean, error?: string}> {
268292
// Auto-detect provider based on key format if not specified
269293
if (!provider) {
270294
if (apiKey.trim().startsWith('sk-')) {
271-
provider = "openai";
272-
console.log("Auto-detected OpenAI API key format for testing");
295+
if (apiKey.trim().startsWith('sk-ant-')) {
296+
provider = "anthropic";
297+
console.log("Auto-detected Anthropic API key format for testing");
298+
} else {
299+
provider = "openai";
300+
console.log("Auto-detected OpenAI API key format for testing");
301+
}
273302
} else {
274303
provider = "gemini";
275304
console.log("Using Gemini API key format for testing (default)");
@@ -280,6 +309,8 @@ export class ConfigHelper extends EventEmitter {
280309
return this.testOpenAIKey(apiKey);
281310
} else if (provider === "gemini") {
282311
return this.testGeminiKey(apiKey);
312+
} else if (provider === "anthropic") {
313+
return this.testAnthropicKey(apiKey);
283314
}
284315

285316
return { valid: false, error: "Unknown API provider" };
@@ -338,6 +369,31 @@ export class ConfigHelper extends EventEmitter {
338369
return { valid: false, error: errorMessage };
339370
}
340371
}
372+
373+
/**
374+
* Test Anthropic API key
375+
* Note: This is a simplified implementation since we don't have the actual Anthropic client
376+
*/
377+
private async testAnthropicKey(apiKey: string): Promise<{valid: boolean, error?: string}> {
378+
try {
379+
// For now, we'll just do a basic check to ensure the key exists and has valid format
380+
// In production, you would connect to the Anthropic API and validate the key
381+
if (apiKey && /^sk-ant-[a-zA-Z0-9]{32,}$/.test(apiKey.trim())) {
382+
// Here you would actually validate the key with an Anthropic API call
383+
return { valid: true };
384+
}
385+
return { valid: false, error: 'Invalid Anthropic API key format.' };
386+
} catch (error: any) {
387+
console.error('Anthropic API key test failed:', error);
388+
let errorMessage = 'Unknown error validating Anthropic API key';
389+
390+
if (error.message) {
391+
errorMessage = `Error: ${error.message}`;
392+
}
393+
394+
return { valid: false, error: errorMessage };
395+
}
396+
}
341397
}
342398

343399
// Export a singleton instance

0 commit comments

Comments
 (0)