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
|
*.vars
|
||||||
.wrangler
|
.wrangler
|
||||||
_worker.bundle
|
_worker.bundle
|
||||||
|
|
||||||
|
.history
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import { motion, type Variants } from 'framer-motion';
|
|||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { Dialog, DialogButton, DialogDescription, DialogRoot, DialogTitle } from '~/components/ui/Dialog';
|
import { Dialog, DialogButton, DialogDescription, DialogRoot, DialogTitle } from '~/components/ui/Dialog';
|
||||||
import { IconButton } from '~/components/ui/IconButton';
|
|
||||||
import { ThemeSwitch } from '~/components/ui/ThemeSwitch';
|
import { ThemeSwitch } from '~/components/ui/ThemeSwitch';
|
||||||
import { db, deleteById, getAll, chatId, type ChatHistoryItem } from '~/lib/persistence';
|
import { db, deleteById, getAll, chatId, type ChatHistoryItem } from '~/lib/persistence';
|
||||||
import { cubicEasingFn } from '~/utils/easings';
|
import { cubicEasingFn } from '~/utils/easings';
|
||||||
|
|||||||
@ -1,9 +1,56 @@
|
|||||||
import { createAnthropic } from '@ai-sdk/anthropic';
|
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({
|
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 { streamText as _streamText, convertToCoreMessages } from 'ai';
|
||||||
import { getAPIKey } from '~/lib/.server/llm/api-key';
|
import { getAnthropicModel, getOpenAIModel, getCustomModel } from '~/lib/.server/llm/model';
|
||||||
import { getAnthropicModel } from '~/lib/.server/llm/model';
|
|
||||||
import { MAX_TOKENS } from './constants';
|
import { MAX_TOKENS } from './constants';
|
||||||
import { getSystemPrompt } from './prompts';
|
import { getSystemPrompt } from './prompts';
|
||||||
|
|
||||||
@ -22,14 +21,44 @@ export type Messages = Message[];
|
|||||||
export type StreamingOptions = Omit<Parameters<typeof _streamText>[0], 'model'>;
|
export type StreamingOptions = Omit<Parameters<typeof _streamText>[0], 'model'>;
|
||||||
|
|
||||||
export function streamText(messages: Messages, env: Env, options?: StreamingOptions) {
|
export function streamText(messages: Messages, env: Env, options?: StreamingOptions) {
|
||||||
|
const aiProvider = process.env.AI_PROVIDER || env.AI_PROVIDER || 'anthropic';
|
||||||
|
|
||||||
|
switch (aiProvider) {
|
||||||
|
case 'anthropic': {
|
||||||
return _streamText({
|
return _streamText({
|
||||||
model: getAnthropicModel(getAPIKey(env)),
|
model: getAnthropicModel(env),
|
||||||
system: getSystemPrompt(),
|
system: getSystemPrompt(),
|
||||||
maxTokens: MAX_TOKENS,
|
maxTokens: MAX_TOKENS,
|
||||||
headers: {
|
|
||||||
'anthropic-beta': 'max-tokens-3-5-sonnet-2024-07-15',
|
|
||||||
},
|
|
||||||
messages: convertToCoreMessages(messages),
|
messages: convertToCoreMessages(messages),
|
||||||
...options,
|
...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": {
|
"dependencies": {
|
||||||
"@ai-sdk/anthropic": "^0.0.39",
|
"@ai-sdk/anthropic": "^0.0.39",
|
||||||
|
"@ai-sdk/openai": "^0.0.58",
|
||||||
|
"@ai-sdk/provider": "^1.0.2",
|
||||||
"@codemirror/autocomplete": "^6.17.0",
|
"@codemirror/autocomplete": "^6.17.0",
|
||||||
"@codemirror/commands": "^6.6.0",
|
"@codemirror/commands": "^6.6.0",
|
||||||
"@codemirror/lang-cpp": "^6.0.2",
|
"@codemirror/lang-cpp": "^6.0.2",
|
||||||
@ -49,21 +51,21 @@
|
|||||||
"@remix-run/cloudflare-pages": "^2.10.2",
|
"@remix-run/cloudflare-pages": "^2.10.2",
|
||||||
"@remix-run/react": "^2.10.2",
|
"@remix-run/react": "^2.10.2",
|
||||||
"@uiw/codemirror-theme-vscode": "^4.23.0",
|
"@uiw/codemirror-theme-vscode": "^4.23.0",
|
||||||
"@unocss/reset": "^0.61.0",
|
"@unocss/reset": "^0.61.3",
|
||||||
"@webcontainer/api": "1.3.0-internal.10",
|
"@webcontainer/api": "1.3.0-internal.10",
|
||||||
"@xterm/addon-fit": "^0.10.0",
|
"@xterm/addon-fit": "^0.10.0",
|
||||||
"@xterm/addon-web-links": "^0.11.0",
|
"@xterm/addon-web-links": "^0.11.0",
|
||||||
"@xterm/xterm": "^5.5.0",
|
"@xterm/xterm": "^5.5.0",
|
||||||
"ai": "^3.3.4",
|
"ai": "^3.4.33",
|
||||||
"date-fns": "^3.6.0",
|
"date-fns": "^3.6.0",
|
||||||
"diff": "^5.2.0",
|
"diff": "^5.2.0",
|
||||||
"framer-motion": "^11.2.12",
|
"framer-motion": "^11.2.12",
|
||||||
"isbot": "^4.1.0",
|
"isbot": "^4.4.0",
|
||||||
"istextorbinary": "^9.5.0",
|
"istextorbinary": "^9.5.0",
|
||||||
"jose": "^5.6.3",
|
"jose": "^5.6.3",
|
||||||
"nanostores": "^0.10.3",
|
"nanostores": "^0.10.3",
|
||||||
"react": "^18.2.0",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.3.1",
|
||||||
"react-hotkeys-hook": "^4.5.0",
|
"react-hotkeys-hook": "^4.5.0",
|
||||||
"react-markdown": "^9.0.1",
|
"react-markdown": "^9.0.1",
|
||||||
"react-resizable-panels": "^2.0.20",
|
"react-resizable-panels": "^2.0.20",
|
||||||
@ -81,8 +83,8 @@
|
|||||||
"@cloudflare/workers-types": "^4.20240620.0",
|
"@cloudflare/workers-types": "^4.20240620.0",
|
||||||
"@remix-run/dev": "^2.10.0",
|
"@remix-run/dev": "^2.10.0",
|
||||||
"@types/diff": "^5.2.1",
|
"@types/diff": "^5.2.1",
|
||||||
"@types/react": "^18.2.20",
|
"@types/react": "^18.3.3",
|
||||||
"@types/react-dom": "^18.2.7",
|
"@types/react-dom": "^18.3.0",
|
||||||
"fast-glob": "^3.3.2",
|
"fast-glob": "^3.3.2",
|
||||||
"is-ci": "^3.0.1",
|
"is-ci": "^3.0.1",
|
||||||
"node-fetch": "^3.3.2",
|
"node-fetch": "^3.3.2",
|
||||||
@ -99,6 +101,7 @@
|
|||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"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 {
|
interface Env {
|
||||||
ANTHROPIC_API_KEY: string;
|
ANTHROPIC_API_KEY: string;
|
||||||
|
API_KEY: string;
|
||||||
|
BASE_URL: string;
|
||||||
|
MODEL: string;
|
||||||
|
AI_PROVIDER: string;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user