redesign fully scaffolded and web login works
This commit is contained in:
@@ -1,8 +1,5 @@
|
||||
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
||||
import { ChatAnthropic } from '@langchain/anthropic';
|
||||
import { ChatOpenAI } from '@langchain/openai';
|
||||
import { ChatGoogleGenerativeAI } from '@langchain/google-genai';
|
||||
import { ChatOpenRouter } from '@langchain/openrouter';
|
||||
import type { FastifyBaseLogger } from 'fastify';
|
||||
|
||||
/**
|
||||
@@ -10,9 +7,6 @@ import type { FastifyBaseLogger } from 'fastify';
|
||||
*/
|
||||
export enum LLMProvider {
|
||||
ANTHROPIC = 'anthropic',
|
||||
OPENAI = 'openai',
|
||||
GOOGLE = 'google',
|
||||
OPENROUTER = 'openrouter',
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -30,9 +24,6 @@ export interface ModelConfig {
|
||||
*/
|
||||
export interface ProviderConfig {
|
||||
anthropicApiKey?: string;
|
||||
openaiApiKey?: string;
|
||||
googleApiKey?: string;
|
||||
openrouterApiKey?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,15 +52,6 @@ export class LLMProviderFactory {
|
||||
case LLMProvider.ANTHROPIC:
|
||||
return this.createAnthropicModel(modelConfig);
|
||||
|
||||
case LLMProvider.OPENAI:
|
||||
return this.createOpenAIModel(modelConfig);
|
||||
|
||||
case LLMProvider.GOOGLE:
|
||||
return this.createGoogleModel(modelConfig);
|
||||
|
||||
case LLMProvider.OPENROUTER:
|
||||
return this.createOpenRouterModel(modelConfig);
|
||||
|
||||
default:
|
||||
throw new Error(`Unsupported provider: ${modelConfig.provider}`);
|
||||
}
|
||||
@@ -91,88 +73,18 @@ export class LLMProviderFactory {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create OpenAI GPT model
|
||||
*/
|
||||
private createOpenAIModel(config: ModelConfig): ChatOpenAI {
|
||||
if (!this.config.openaiApiKey) {
|
||||
throw new Error('OpenAI API key not configured');
|
||||
}
|
||||
|
||||
return new ChatOpenAI({
|
||||
model: config.model,
|
||||
temperature: config.temperature ?? 0.7,
|
||||
maxTokens: config.maxTokens ?? 4096,
|
||||
openAIApiKey: this.config.openaiApiKey,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Google Gemini model
|
||||
*/
|
||||
private createGoogleModel(config: ModelConfig): ChatGoogleGenerativeAI {
|
||||
if (!this.config.googleApiKey) {
|
||||
throw new Error('Google API key not configured');
|
||||
}
|
||||
|
||||
return new ChatGoogleGenerativeAI({
|
||||
model: config.model,
|
||||
temperature: config.temperature ?? 0.7,
|
||||
maxOutputTokens: config.maxTokens ?? 4096,
|
||||
apiKey: this.config.googleApiKey,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create OpenRouter model (access to 300+ models)
|
||||
*/
|
||||
private createOpenRouterModel(config: ModelConfig): ChatOpenRouter {
|
||||
if (!this.config.openrouterApiKey) {
|
||||
throw new Error('OpenRouter API key not configured');
|
||||
}
|
||||
|
||||
return new ChatOpenRouter({
|
||||
model: config.model,
|
||||
temperature: config.temperature ?? 0.7,
|
||||
maxTokens: config.maxTokens ?? 4096,
|
||||
apiKey: this.config.openrouterApiKey,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default model based on environment
|
||||
*/
|
||||
getDefaultModel(): ModelConfig {
|
||||
// Check which API keys are available
|
||||
if (this.config.anthropicApiKey) {
|
||||
return {
|
||||
provider: LLMProvider.ANTHROPIC,
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
};
|
||||
if (!this.config.anthropicApiKey) {
|
||||
throw new Error('Anthropic API key not configured');
|
||||
}
|
||||
|
||||
if (this.config.openaiApiKey) {
|
||||
return {
|
||||
provider: LLMProvider.OPENAI,
|
||||
model: 'gpt-4o',
|
||||
};
|
||||
}
|
||||
|
||||
if (this.config.googleApiKey) {
|
||||
return {
|
||||
provider: LLMProvider.GOOGLE,
|
||||
model: 'gemini-2.0-flash-exp',
|
||||
};
|
||||
}
|
||||
|
||||
if (this.config.openrouterApiKey) {
|
||||
return {
|
||||
provider: LLMProvider.OPENROUTER,
|
||||
model: 'anthropic/claude-3.5-sonnet',
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error('No LLM API keys configured');
|
||||
return {
|
||||
provider: LLMProvider.ANTHROPIC,
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +92,6 @@ export class LLMProviderFactory {
|
||||
* Predefined model configurations
|
||||
*/
|
||||
export const MODELS = {
|
||||
// Anthropic
|
||||
CLAUDE_SONNET: {
|
||||
provider: LLMProvider.ANTHROPIC,
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
@@ -193,24 +104,4 @@ export const MODELS = {
|
||||
provider: LLMProvider.ANTHROPIC,
|
||||
model: 'claude-3-opus-20240229',
|
||||
},
|
||||
|
||||
// OpenAI
|
||||
GPT4O: {
|
||||
provider: LLMProvider.OPENAI,
|
||||
model: 'gpt-4o',
|
||||
},
|
||||
GPT4O_MINI: {
|
||||
provider: LLMProvider.OPENAI,
|
||||
model: 'gpt-4o-mini',
|
||||
},
|
||||
|
||||
// Google
|
||||
GEMINI_2_FLASH: {
|
||||
provider: LLMProvider.GOOGLE,
|
||||
model: 'gemini-2.0-flash-exp',
|
||||
},
|
||||
GEMINI_PRO: {
|
||||
provider: LLMProvider.GOOGLE,
|
||||
model: 'gemini-1.5-pro',
|
||||
},
|
||||
} as const satisfies Record<string, ModelConfig>;
|
||||
|
||||
@@ -108,11 +108,11 @@ export class ModelRouter {
|
||||
// Pro users get good models
|
||||
return isComplex
|
||||
? { provider: LLMProvider.ANTHROPIC, model: 'claude-3-5-sonnet-20241022' }
|
||||
: { provider: LLMProvider.OPENAI, model: 'gpt-4o-mini' };
|
||||
: { provider: LLMProvider.ANTHROPIC, model: 'claude-3-5-haiku-20241022' };
|
||||
}
|
||||
|
||||
// Free users get efficient models
|
||||
return { provider: LLMProvider.GOOGLE, model: 'gemini-2.0-flash-exp' };
|
||||
return { provider: LLMProvider.ANTHROPIC, model: 'claude-3-5-haiku-20241022' };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,10 +124,10 @@ export class ModelRouter {
|
||||
return { provider: LLMProvider.ANTHROPIC, model: 'claude-3-5-sonnet-20241022' };
|
||||
|
||||
case 'pro':
|
||||
return { provider: LLMProvider.OPENAI, model: 'gpt-4o' };
|
||||
return { provider: LLMProvider.ANTHROPIC, model: 'claude-3-5-sonnet-20241022' };
|
||||
|
||||
case 'free':
|
||||
return { provider: LLMProvider.GOOGLE, model: 'gemini-2.0-flash-exp' };
|
||||
return { provider: LLMProvider.ANTHROPIC, model: 'claude-3-5-haiku-20241022' };
|
||||
|
||||
default:
|
||||
return this.defaultModel;
|
||||
@@ -137,23 +137,18 @@ export class ModelRouter {
|
||||
/**
|
||||
* Route to cheapest available model
|
||||
*/
|
||||
private routeByCost(license: UserLicense): ModelConfig {
|
||||
// Free tier: use cheapest
|
||||
if (license.licenseType === 'free') {
|
||||
return { provider: LLMProvider.GOOGLE, model: 'gemini-2.0-flash-exp' };
|
||||
}
|
||||
|
||||
// Paid tiers: use GPT-4o-mini for cost efficiency
|
||||
return { provider: LLMProvider.OPENAI, model: 'gpt-4o-mini' };
|
||||
private routeByCost(_license: UserLicense): ModelConfig {
|
||||
// All tiers: use Haiku for cost efficiency
|
||||
return { provider: LLMProvider.ANTHROPIC, model: 'claude-3-5-haiku-20241022' };
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if model is allowed for user's license
|
||||
*/
|
||||
private isModelAllowed(model: ModelConfig, license: UserLicense): boolean {
|
||||
// Free tier: only cheap models
|
||||
// Free tier: only Haiku
|
||||
if (license.licenseType === 'free') {
|
||||
const allowedModels = ['gemini-2.0-flash-exp', 'gpt-4o-mini', 'claude-3-5-haiku-20241022'];
|
||||
const allowedModels = ['claude-3-5-haiku-20241022'];
|
||||
return allowedModels.includes(model.model);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user