Skip to content

Commit 672e9f8

Browse files
feat: add support for multiple AI providers (OpenAI, Google, OpenRouter) with configurable models
1 parent 2dba54c commit 672e9f8

File tree

5 files changed

+148
-17
lines changed

5 files changed

+148
-17
lines changed

.env.example

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,15 @@
1+
# AI Model Configuration
2+
# Choose your provider: 'openai', 'google', or 'openrouter'
3+
AI_PROVIDER=openai
4+
5+
# Specify the model ID for your chosen provider
6+
# Examples:
7+
# - OpenAI: gpt-4-turbo, gpt-4, gpt-3.5-turbo
8+
# - Google: gemini-1.5-pro, gemini-1.5-flash
9+
# - OpenRouter: openai/gpt-4-turbo, anthropic/claude-3.5-sonnet
10+
AI_MODEL=gpt-4.1-2025-04-14
11+
12+
# API Keys for each provider (only set the one you're using)
113
OPENAI_API_KEY=
2-
OPENAI_MODEL=gpt-4.1-2025-04-14
14+
GOOGLE_GENERATIVE_AI_API_KEY=
15+
OPENROUTER_API_KEY=

app/api/chat/route.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
import { ProvideLinksToolSchema } from '@/lib/ai-tools/inkeep-qa-schema';
22
import { SearchDocsToolSchema, searchAndFetchDocs } from '@/lib/ai-tools/search-and-fetch';
3-
import { createOpenAI } from '@ai-sdk/openai';
43
import { convertToModelMessages, stepCountIs, streamText } from 'ai';
54
import { systemPrompt } from '@/lib/searchPrompt';
6-
import {validateRateLimit} from '@/utils/rateLimit';
5+
import { validateRateLimit } from '@/utils/rateLimit';
6+
import { createModel } from '@/lib/ai-models';
77

8-
const openai = createOpenAI({
9-
apiKey: process.env.OPENAI_API_KEY,
10-
});
118

129
export async function POST(req: Request) {
1310
const rateLimitError = validateRateLimit(req);
@@ -20,21 +17,21 @@ export async function POST(req: Request) {
2017
}
2118

2219
const result = streamText({
23-
model: openai(process.env.OPENAI_MODEL ?? 'gpt-4.1-2025-04-14'),
20+
model: createModel(),
2421
tools: {
2522
searchDocs: {
2623
description: 'Search the NocoDB documentation and retrieve full page content. After calling this, you MUST read the returned content and write a comprehensive answer for the user based on that content.',
2724
inputSchema: SearchDocsToolSchema,
2825
execute: async ({ query }: { query: string }) => {
2926
const { markdown, links } = await searchAndFetchDocs(query, 3);
30-
return {markdown, links};
27+
return { markdown, links };
3128
},
3229
},
3330
provideLinks: {
3431
inputSchema: ProvideLinksToolSchema,
3532
},
3633
},
37-
system: systemPrompt,
34+
system: systemPrompt,
3835
messages: convertToModelMessages(reqJson.messages, {
3936
ignoreIncompleteToolCalls: true,
4037
}),

lib/ai-models.ts

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { openai, createOpenAI } from '@ai-sdk/openai';
2+
import { google, createGoogleGenerativeAI } from '@ai-sdk/google';
3+
import { createOpenRouter } from '@openrouter/ai-sdk-provider';
4+
import type { LanguageModel } from 'ai';
5+
6+
export type ModelProvider = 'openai' | 'google' | 'openrouter';
7+
8+
/**
9+
* Create a model instance based on environment configuration
10+
* Reads from:
11+
* - AI_PROVIDER: 'openai' | 'google' | 'openrouter' (default: 'openai')
12+
* - AI_MODEL: model identifier (e.g., 'gpt-4', 'gemini-1.5-pro', 'openai/gpt-4')
13+
* - OPENAI_API_KEY: for OpenAI provider (optional, uses default if not set)
14+
* - GOOGLE_GENERATIVE_AI_API_KEY: for Google provider (optional, uses default if not set)
15+
* - OPENROUTER_API_KEY: for OpenRouter provider (required for OpenRouter)
16+
*/
17+
export function createModel(): LanguageModel {
18+
const provider = (process.env.AI_PROVIDER as ModelProvider) || 'openai';
19+
const modelId = process.env.AI_MODEL;
20+
21+
switch (provider) {
22+
case 'openai': {
23+
const model = modelId || 'gpt-4-turbo';
24+
// If custom API key is provided, create custom client
25+
if (process.env.OPENAI_API_KEY) {
26+
const customOpenAI = createOpenAI({
27+
apiKey: process.env.OPENAI_API_KEY,
28+
});
29+
return customOpenAI(model);
30+
}
31+
return openai(model);
32+
}
33+
case 'google': {
34+
const model = modelId || 'gemini-1.5-pro';
35+
// If custom API key is provided, create custom client
36+
if (process.env.GOOGLE_GENERATIVE_AI_API_KEY) {
37+
const customGoogle = createGoogleGenerativeAI({
38+
apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY,
39+
});
40+
return customGoogle(model);
41+
}
42+
return google(model);
43+
}
44+
case 'openrouter': {
45+
const model = modelId || 'openai/gpt-4-turbo';
46+
const openrouter = createOpenRouter({
47+
apiKey: process.env.OPENROUTER_API_KEY || '',
48+
});
49+
return openrouter(model);
50+
}
51+
default:
52+
throw new Error(`Unsupported AI provider: ${provider}. Use 'openai', 'google', or 'openrouter'.`);
53+
}
54+
}
55+
56+
/**
57+
* Create a model with custom provider and model ID
58+
* Useful for switching models dynamically
59+
*/
60+
export function createCustomModel(
61+
provider: ModelProvider,
62+
modelId: string,
63+
apiKey?: string
64+
): LanguageModel {
65+
switch (provider) {
66+
case 'openai': {
67+
if (apiKey) {
68+
const customOpenAI = createOpenAI({ apiKey });
69+
return customOpenAI(modelId);
70+
}
71+
return openai(modelId);
72+
}
73+
case 'google': {
74+
if (apiKey) {
75+
const customGoogle = createGoogleGenerativeAI({ apiKey });
76+
return customGoogle(modelId);
77+
}
78+
return google(modelId);
79+
}
80+
case 'openrouter': {
81+
const openrouter = createOpenRouter({
82+
apiKey: apiKey || process.env.OPENROUTER_API_KEY || '',
83+
});
84+
return openrouter(modelId);
85+
}
86+
default:
87+
throw new Error(`Unsupported provider: ${provider}`);
88+
}
89+
}

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616
"postbuild": "next-sitemap && npm run generate-blog-sitemap && npm run generate-llm-content"
1717
},
1818
"dependencies": {
19+
"@ai-sdk/google": "^2.0.23",
1920
"@ai-sdk/openai": "^2.0.52",
2021
"@ai-sdk/react": "^2.0.59",
2122
"@icons-pack/react-simple-icons": "^13.8.0",
23+
"@openrouter/ai-sdk-provider": "^1.2.0",
2224
"@radix-ui/react-collapsible": "^1.1.8",
2325
"@radix-ui/react-dialog": "^1.1.13",
2426
"@radix-ui/react-dropdown-menu": "^2.1.7",

pnpm-lock.yaml

Lines changed: 38 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)