Added the ability to use practically any LLM you can dream of within Bolt.new

This commit is contained in:
Cole Medin
2024-10-13 13:53:43 -05:00
parent ffa9f11360
commit 90a206f2d4
14 changed files with 642 additions and 126 deletions

View File

@@ -1,9 +1,20 @@
// @ts-nocheck
// Preventing TS checks with files presented in the video for a better presentation.
import { env } from 'node:process';
export function getAPIKey(cloudflareEnv: Env) {
export function getAPIKey(cloudflareEnv: Env, provider: string) {
/**
* The `cloudflareEnv` is only used when deployed or when previewing locally.
* In development the environment variables are available through `env`.
*/
return env.ANTHROPIC_API_KEY || cloudflareEnv.ANTHROPIC_API_KEY;
switch (provider) {
case 'Anthropic':
return env.ANTHROPIC_API_KEY || cloudflareEnv.ANTHROPIC_API_KEY;
case 'OpenAI':
return env.OPENAI_API_KEY || cloudflareEnv.OPENAI_API_KEY;
case 'Groq':
return env.GROQ_API_KEY || cloudflareEnv.GROQ_API_KEY;
default:
return "";
}
}

View File

@@ -1,9 +1,50 @@
// @ts-nocheck
// Preventing TS checks with files presented in the video for a better presentation.
import { getAPIKey } from '~/lib/.server/llm/api-key';
import { createAnthropic } from '@ai-sdk/anthropic';
import { createOpenAI } from '@ai-sdk/openai';
import { ollama } from 'ollama-ai-provider';
export function getAnthropicModel(apiKey: string) {
export function getAnthropicModel(apiKey: string, model: string) {
const anthropic = createAnthropic({
apiKey,
});
return anthropic('claude-3-5-sonnet-20240620');
return anthropic(model);
}
export function getOpenAIModel(apiKey: string, model: string) {
const openai = createOpenAI({
apiKey,
});
return openai(model);
}
export function getGroqModel(apiKey: string, model: string) {
const openai = createOpenAI({
baseURL: 'https://api.groq.com/openai/v1',
apiKey,
});
return openai(model);
}
export function getOllamaModel(model: string) {
return ollama(model);
}
export function getModel(provider: string, model: string, env: Env) {
const apiKey = getAPIKey(env, provider);
switch (provider) {
case 'Anthropic':
return getAnthropicModel(apiKey, model);
case 'OpenAI':
return getOpenAIModel(apiKey, model);
case 'Groq':
return getGroqModel(apiKey, model);
default:
return getOllamaModel(model);
}
}

View File

@@ -1,8 +1,10 @@
// @ts-nocheck
// Preventing TS checks with files presented in the video for a better presentation.
import { streamText as _streamText, convertToCoreMessages } from 'ai';
import { getAPIKey } from '~/lib/.server/llm/api-key';
import { getAnthropicModel } from '~/lib/.server/llm/model';
import { getModel } from '~/lib/.server/llm/model';
import { MAX_TOKENS } from './constants';
import { getSystemPrompt } from './prompts';
import { MODEL_LIST, DEFAULT_MODEL, DEFAULT_PROVIDER } from '~/utils/constants';
interface ToolResult<Name extends string, Args, Result> {
toolCallId: string;
@@ -15,21 +17,50 @@ interface Message {
role: 'user' | 'assistant';
content: string;
toolInvocations?: ToolResult<string, unknown, unknown>[];
model?: string;
}
export type Messages = Message[];
export type StreamingOptions = Omit<Parameters<typeof _streamText>[0], 'model'>;
function extractModelFromMessage(message: Message): { model: string; content: string } {
const modelRegex = /^\[Model: (.*?)\]\n\n/;
const match = message.content.match(modelRegex);
if (match) {
const model = match[1];
const content = message.content.replace(modelRegex, '');
return { model, content };
}
// Default model if not specified
return { model: DEFAULT_MODEL, content: message.content };
}
export function streamText(messages: Messages, env: Env, options?: StreamingOptions) {
let currentModel = DEFAULT_MODEL;
const processedMessages = messages.map((message) => {
if (message.role === 'user') {
const { model, content } = extractModelFromMessage(message);
if (model && MODEL_LIST.find((m) => m.name === model)) {
currentModel = model; // Update the current model
}
return { ...message, content };
}
return message;
});
const provider = MODEL_LIST.find((model) => model.name === currentModel)?.provider || DEFAULT_PROVIDER;
return _streamText({
model: getAnthropicModel(getAPIKey(env)),
model: getModel(provider, currentModel, env),
system: getSystemPrompt(),
maxTokens: MAX_TOKENS,
headers: {
'anthropic-beta': 'max-tokens-3-5-sonnet-2024-07-15',
},
messages: convertToCoreMessages(messages),
// headers: {
// 'anthropic-beta': 'max-tokens-3-5-sonnet-2024-07-15',
// },
messages: convertToCoreMessages(processedMessages),
...options,
});
}