mirror of
https://github.com/stackblitz/bolt.new
synced 2025-06-26 18:17:50 +00:00
feat: enhance AI model integration and configuration
- Added support for OpenAI alongside existing Anthropic model. - Introduced environment variables for API key, base URL, model, and AI provider. - Updated model selection logic to accommodate multiple AI providers. - Refactored model functions to streamline API key retrieval and model initialization. - Enhanced sidebar component by removing unused imports. Additionally, updated package dependencies and added a new entry to .gitignore for history files.
This commit is contained in:
parent
eda10b1212
commit
4a6d8a3a9f
2
.gitignore
vendored
2
.gitignore
vendored
@ -28,3 +28,5 @@ dist-ssr
|
||||
*.vars
|
||||
.wrangler
|
||||
_worker.bundle
|
||||
|
||||
.history
|
||||
|
||||
@ -2,7 +2,6 @@ import { motion, type Variants } from 'framer-motion';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { toast } from 'react-toastify';
|
||||
import { Dialog, DialogButton, DialogDescription, DialogRoot, DialogTitle } from '~/components/ui/Dialog';
|
||||
import { IconButton } from '~/components/ui/IconButton';
|
||||
import { ThemeSwitch } from '~/components/ui/ThemeSwitch';
|
||||
import { db, deleteById, getAll, chatId, type ChatHistoryItem } from '~/lib/persistence';
|
||||
import { cubicEasingFn } from '~/utils/easings';
|
||||
|
||||
@ -1,9 +1,56 @@
|
||||
import { createAnthropic } from '@ai-sdk/anthropic';
|
||||
import { createOpenAI } from '@ai-sdk/openai';
|
||||
import { getAPIKey } from './api-key';
|
||||
|
||||
export function getAnthropicModel(apiKey: string) {
|
||||
export const aiProvider = {
|
||||
openAI: 'openai',
|
||||
anthropic: 'anthropic',
|
||||
custom: 'custom',
|
||||
} as const;
|
||||
|
||||
export type AiProviderType = (typeof aiProvider)[keyof typeof aiProvider];
|
||||
|
||||
export const defaultModels: Record<AiProviderType, string> = {
|
||||
[aiProvider.openAI]: 'chatgpt-4o-latest',
|
||||
[aiProvider.anthropic]: 'claude-3-5-sonnet-20240620',
|
||||
[aiProvider.custom]: 'llama3.1',
|
||||
} as const;
|
||||
|
||||
export function isValidProvider(provider: string): provider is AiProviderType {
|
||||
return Object.values(aiProvider).includes(provider as AiProviderType);
|
||||
}
|
||||
|
||||
export function getDefaultModel(provider: AiProviderType): string {
|
||||
return defaultModels[provider];
|
||||
}
|
||||
|
||||
export function getAnthropicModel(env: Env) {
|
||||
const defaultModel = getDefaultModel(aiProvider.anthropic);
|
||||
const anthropic = createAnthropic({
|
||||
apiKey,
|
||||
apiKey: getAPIKey(env),
|
||||
});
|
||||
|
||||
return anthropic('claude-3-5-sonnet-20240620');
|
||||
return anthropic(process.env.MODEL || env.MODEL || defaultModel);
|
||||
}
|
||||
|
||||
export function getOpenAIModel(env: Env) {
|
||||
const defaultModel = getDefaultModel(aiProvider.openAI);
|
||||
|
||||
const openai = createOpenAI({
|
||||
compatibility: 'strict', // strict mode, enabled when using the OpenAI API
|
||||
apiKey: process.env.API_KEY || env.API_KEY,
|
||||
});
|
||||
|
||||
return openai(process.env.MODEL || env.MODEL || defaultModel);
|
||||
}
|
||||
|
||||
export function getCustomModel(env: Env) {
|
||||
const defaultModel = getDefaultModel(aiProvider.custom);
|
||||
const openaiCompatible = createOpenAI({
|
||||
compatibility: 'compatible',
|
||||
apiKey: process.env.API_KEY || env.API_KEY || 'bogus', // if local model, do not need api key
|
||||
baseURL: process.env.BASE_URL || env.BASE_URL || 'http://localhost:11434/v1',
|
||||
});
|
||||
|
||||
return openaiCompatible(process.env.MODEL || env.MODEL || defaultModel);
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { streamText as _streamText, convertToCoreMessages } from 'ai';
|
||||
import { getAPIKey } from '~/lib/.server/llm/api-key';
|
||||
import { getAnthropicModel } from '~/lib/.server/llm/model';
|
||||
import { getAnthropicModel, getOpenAIModel, getCustomModel } from '~/lib/.server/llm/model';
|
||||
import { MAX_TOKENS } from './constants';
|
||||
import { getSystemPrompt } from './prompts';
|
||||
|
||||
@ -22,14 +21,44 @@ export type Messages = Message[];
|
||||
export type StreamingOptions = Omit<Parameters<typeof _streamText>[0], 'model'>;
|
||||
|
||||
export function streamText(messages: Messages, env: Env, options?: StreamingOptions) {
|
||||
return _streamText({
|
||||
model: getAnthropicModel(getAPIKey(env)),
|
||||
system: getSystemPrompt(),
|
||||
maxTokens: MAX_TOKENS,
|
||||
headers: {
|
||||
'anthropic-beta': 'max-tokens-3-5-sonnet-2024-07-15',
|
||||
},
|
||||
messages: convertToCoreMessages(messages),
|
||||
...options,
|
||||
});
|
||||
const aiProvider = process.env.AI_PROVIDER || env.AI_PROVIDER || 'anthropic';
|
||||
|
||||
switch (aiProvider) {
|
||||
case 'anthropic': {
|
||||
return _streamText({
|
||||
model: getAnthropicModel(env),
|
||||
system: getSystemPrompt(),
|
||||
maxTokens: MAX_TOKENS,
|
||||
messages: convertToCoreMessages(messages),
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
case 'openai': {
|
||||
return _streamText({
|
||||
model: getOpenAIModel(env),
|
||||
system: getSystemPrompt(),
|
||||
maxTokens: MAX_TOKENS,
|
||||
messages: convertToCoreMessages(messages),
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
case 'custom': {
|
||||
console.log('1111', messages);
|
||||
console.log('222', process.env.MODEL);
|
||||
|
||||
return _streamText({
|
||||
model: getCustomModel(env),
|
||||
system: getSystemPrompt(),
|
||||
maxTokens: MAX_TOKENS,
|
||||
messages,
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
default: {
|
||||
throw new Error(`Invalid AI provider: ${aiProvider}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
19
package.json
19
package.json
@ -24,6 +24,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@ai-sdk/anthropic": "^0.0.39",
|
||||
"@ai-sdk/openai": "^0.0.58",
|
||||
"@ai-sdk/provider": "^1.0.2",
|
||||
"@codemirror/autocomplete": "^6.17.0",
|
||||
"@codemirror/commands": "^6.6.0",
|
||||
"@codemirror/lang-cpp": "^6.0.2",
|
||||
@ -49,21 +51,21 @@
|
||||
"@remix-run/cloudflare-pages": "^2.10.2",
|
||||
"@remix-run/react": "^2.10.2",
|
||||
"@uiw/codemirror-theme-vscode": "^4.23.0",
|
||||
"@unocss/reset": "^0.61.0",
|
||||
"@unocss/reset": "^0.61.3",
|
||||
"@webcontainer/api": "1.3.0-internal.10",
|
||||
"@xterm/addon-fit": "^0.10.0",
|
||||
"@xterm/addon-web-links": "^0.11.0",
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
"ai": "^3.3.4",
|
||||
"ai": "^3.4.33",
|
||||
"date-fns": "^3.6.0",
|
||||
"diff": "^5.2.0",
|
||||
"framer-motion": "^11.2.12",
|
||||
"isbot": "^4.1.0",
|
||||
"isbot": "^4.4.0",
|
||||
"istextorbinary": "^9.5.0",
|
||||
"jose": "^5.6.3",
|
||||
"nanostores": "^0.10.3",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-hotkeys-hook": "^4.5.0",
|
||||
"react-markdown": "^9.0.1",
|
||||
"react-resizable-panels": "^2.0.20",
|
||||
@ -81,8 +83,8 @@
|
||||
"@cloudflare/workers-types": "^4.20240620.0",
|
||||
"@remix-run/dev": "^2.10.0",
|
||||
"@types/diff": "^5.2.1",
|
||||
"@types/react": "^18.2.20",
|
||||
"@types/react-dom": "^18.2.7",
|
||||
"@types/react": "^18.3.3",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"fast-glob": "^3.3.2",
|
||||
"is-ci": "^3.0.1",
|
||||
"node-fetch": "^3.3.2",
|
||||
@ -99,6 +101,7 @@
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"resolutions": {
|
||||
"@typescript-eslint/utils": "^8.0.0-alpha.30"
|
||||
"@typescript-eslint/utils": "^8.0.0-alpha.30",
|
||||
"@ai-sdk/provider": "1.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
680
pnpm-lock.yaml
680
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
4
worker-configuration.d.ts
vendored
4
worker-configuration.d.ts
vendored
@ -1,3 +1,7 @@
|
||||
interface Env {
|
||||
ANTHROPIC_API_KEY: string;
|
||||
API_KEY: string;
|
||||
BASE_URL: string;
|
||||
MODEL: string;
|
||||
AI_PROVIDER: string;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user