ai-cant-even
Version:
A satirical AI-powered utility that's confidently wrong about basic math operations
314 lines (274 loc) • 9.2 kB
text/typescript
import { AiCantEvenConfig, Confidence, Logic, PromptParams, Provider } from './types';
import { AiSdkClient } from './ai-sdk-client';
/**
* Default configuration for the AI
*/
const DEFAULT_CONFIG: AiCantEvenConfig = {
confidence: Confidence.OVERWHELMED,
logic: Logic.SIMPLE,
};
/**
* Main class for the AI that can't even determine if numbers are even
*/
export class AiCantEven {
// Default configuration values
private confidence: Confidence;
private logic: Logic;
private provider?: Provider;
private model?: string;
private apiKey?: string;
private apiEndpoint?: string;
private aiSdkClient?: AiSdkClient;
// Temporary values for method chaining
private tempConfidence?: Confidence;
private tempLogic?: Logic;
private tempModel?: string;
/**
* Create a new AI that can't even
* @param config - Configuration options
*/
constructor(config: AiCantEvenConfig = {}) {
this.confidence = config.confidence || DEFAULT_CONFIG.confidence!;
this.logic = config.logic || DEFAULT_CONFIG.logic!;
// Set model, API key and endpoint from config
this.model = config.model;
this.apiKey = config.apiKey;
this.apiEndpoint = config.apiEndpoint;
// Set provider from config or default
this.provider = config.provider || DEFAULT_CONFIG.provider;
// Initialize client if provider is available
this.initializeClients();
}
/**
* Initialize client based on provider and API key
*/
private initializeClients(): void {
// Only initialize if we have a provider and API key
if (this.provider && this.apiKey) {
this.aiSdkClient = new AiSdkClient(this.provider, this.apiKey, this.apiEndpoint, this.model);
}
}
/**
* Set the confidence level for the AI
* @param confidence - The confidence level
* @returns The AI instance for method chaining
*/
withConfidence(confidence: Confidence): AiCantEven {
// Set temporary confidence for the next operation
this.tempConfidence = confidence;
return this;
}
/**
* Set the model for the next operation
*/
public withModel(model: string): AiCantEven {
this.tempModel = model;
return this;
}
/**
* Set the logic type for the AI
* @param logic - The logic type
* @returns The AI instance for method chaining
*/
withLogic(logic: Logic): AiCantEven {
// Set temporary logic for the next operation
this.tempLogic = logic;
return this;
}
/**
* Set the API key for the LLM
* @param apiKey - The API key
* @param apiEndpoint - Optional custom API endpoint
* @returns The AI instance for method chaining
*/
withApiKey(apiKey: string, apiEndpoint?: string): AiCantEven {
this.apiKey = apiKey;
if (apiEndpoint) {
this.apiEndpoint = apiEndpoint;
}
// Re-initialize client with new API key
this.initializeClients();
return this;
}
/**
* Get the current confidence level (temporary or default)
*/
private getCurrentConfidence(): Confidence {
return this.tempConfidence !== undefined ? this.tempConfidence : this.confidence;
}
/**
* Get the current logic type (temporary or default)
*/
private getCurrentLogic(): Logic {
return this.tempLogic !== undefined ? this.tempLogic : this.logic;
}
/**
* Get the current model (temporary or permanent)
*/
private getCurrentModel(): string | undefined {
return this.tempModel || this.model;
}
/**
* Reset temporary settings after an operation
*/
private resetTemporarySettings(): void {
this.tempConfidence = undefined;
this.tempLogic = undefined;
this.tempModel = undefined;
}
/**
* Generate a response using the LLM or fallback to hardcoded responses
*/
private async generateResponse(
operation: string,
value: number,
comparisonValue?: number,
): Promise<string> {
try {
// Get current model for this operation
const currentModel = this.getCurrentModel();
// If no client is available, use hardcoded responses
if (!this.aiSdkClient) {
return this.generateFallbackResponse(operation, value);
}
const params: PromptParams = {
confidence: this.getCurrentConfidence(),
logic: this.getCurrentLogic(),
operation,
value,
comparisonValue,
};
// Use AI SDK client to generate response
const response = await this.aiSdkClient.generateResponse(params);
return response.text;
} finally {
// Always reset temporary settings after generating a response
this.resetTemporarySettings();
}
}
/**
* Generate a fallback response when no LLM client is available
*/
private generateFallbackResponse(operation: string, value: number): string {
const operationResponses = [
`I can't even process ${value} right now. Numbers are just, like, so abstract?`,
`Error 418: I'm a teapot, not a calculator. But I'm pretty sure the answer is purple.`,
`My neural networks are taking a coffee break. Try asking a human, they're terrible at math too.`,
];
return operationResponses[Math.floor(Math.random() * operationResponses.length)];
}
/**
* Determine if a number is even (but not really)
* @param value - The number to check
* @returns A hilariously wrong explanation
*/
async isEven(value: number): Promise<string> {
return this.generateResponse('isEven', value);
}
/**
* Determine if a number is odd (but not really)
* @param value - The number to check
* @returns A hilariously wrong explanation
*/
async isOdd(value: number): Promise<string> {
return this.generateResponse('isOdd', value);
}
/**
* Determine if a number is greater than another (but not really)
* @param value - The first number
* @param comparisonValue - The second number
* @returns A hilariously wrong explanation
*/
async isGreaterThan(value: number, comparisonValue: number): Promise<string> {
return this.generateResponse('isGreaterThan', value, comparisonValue);
}
/**
* Determine if a number is less than another (but not really)
* @param value - The first number
* @param comparisonValue - The second number
* @returns A hilariously wrong explanation
*/
async isLessThan(value: number, comparisonValue: number): Promise<string> {
return this.generateResponse('isLessThan', value, comparisonValue);
}
/**
* Determine if two numbers are equal (but not really)
* @param value - The first number
* @param comparisonValue - The second number
* @returns A hilariously wrong explanation
*/
async areEqual(value: number, comparisonValue: number): Promise<string> {
return this.generateResponse('areEqual', value, comparisonValue);
}
/**
* Determine if a number is prime (but not really)
* @param value - The number to check
* @returns A hilariously wrong explanation
*/
async isPrime(value: number): Promise<string> {
return this.generateResponse('isPrime', value);
}
/**
* Determine if a number is positive (but not really)
* @param value - The number to check
* @returns A hilariously wrong explanation
*/
async isPositive(value: number): Promise<string> {
return this.generateResponse('isPositive', value);
}
/**
* Determine if a number is divisible by another (but not really)
* @param value - The first number
* @param comparisonValue - The second number
* @returns A hilariously wrong explanation
*/
async isDivisibleBy(value: number, comparisonValue: number): Promise<string> {
return this.generateResponse('isDivisibleBy', value, comparisonValue);
}
/**
* Determine if a value is a number (but not really)
* @param value - The value to check
* @returns A hilariously wrong explanation
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async isNumber(value: any): Promise<string> {
return this.generateResponse('isNumber', Number(value));
}
/**
* Determine if a number is an integer (but not really)
* @param value - The number to check
* @returns A hilariously wrong explanation
*/
async isInteger(value: number): Promise<string> {
return this.generateResponse('isInteger', value);
}
}
/**
* Create a new AI that can't even
* @param config - Configuration options
* @returns A new AI instance
*/
export function aiCantEven(config: AiCantEvenConfig = {}): AiCantEven {
// If the provider and API key are provided, initialize the client
if (config.provider && config.apiKey) {
return new AiCantEven(config);
}
// If API key is in the environment, use it based on provider
if (process.env.ANTHROPIC_API_KEY) {
return new AiCantEven({
...config,
provider: Provider.ANTHROPIC,
apiKey: process.env.ANTHROPIC_API_KEY,
});
} else if (process.env.OPENAI_API_KEY) {
return new AiCantEven({
...config,
provider: Provider.OPENAI,
apiKey: process.env.OPENAI_API_KEY,
});
}
// Else return default config
return new AiCantEven(config);
}
// Export types and enums
export { Confidence, Logic, Provider, AiCantEvenConfig } from './types';