diff --git a/env.example b/env.example
index df9dcfc..81edc13 100644
--- a/env.example
+++ b/env.example
@@ -183,6 +183,7 @@ OPENAI_API_KEY=""
REPLICATE_API_TOKEN=""
GOOGLE_GENERATIVE_AI_API_KEY=""
DEEPSEEK_API_KEY=""
+OPENROUTER_API_KEY=""
# -----------------------------------------------------------------------------
# Web Content Analyzer (Firecrawl)
diff --git a/package.json b/package.json
index 8bdc6a0..e65509a 100644
--- a/package.json
+++ b/package.json
@@ -41,6 +41,7 @@
"@mendable/firecrawl-js": "^1.29.1",
"@next/third-parties": "^15.3.0",
"@openpanel/nextjs": "^1.0.7",
+ "@openrouter/ai-sdk-provider": "^1.0.0-beta.6",
"@orama/orama": "^3.1.4",
"@orama/tokenizers": "^3.1.4",
"@radix-ui/react-accordion": "^1.2.3",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 217c320..5b817ad 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -59,6 +59,9 @@ importers:
'@openpanel/nextjs':
specifier: ^1.0.7
version: 1.0.7(next@15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
+ '@openrouter/ai-sdk-provider':
+ specifier: ^1.0.0-beta.6
+ version: 1.0.0-beta.6(ai@5.0.0(zod@4.0.14))(zod@4.0.14)
'@orama/orama':
specifier: ^3.1.4
version: 3.1.4
@@ -1730,6 +1733,13 @@ packages:
'@openpanel/web@1.0.1':
resolution: {integrity: sha512-cVZ7Kr9SicczJ/RDIfEtZs8+1iGDzwkabVA/j3NqSl8VSucsC8m1+LVbjmCDzCJNnK4yVn6tEcc9PJRi2rtllw==}
+ '@openrouter/ai-sdk-provider@1.0.0-beta.6':
+ resolution: {integrity: sha512-1cj8yUek4ib10MqZ+9fw1p1a3SR0Zhx3HH1J3+WQIXXuH/rUhiAkwovgPi1ADuC1QECPSPiwfhK2GecnDm8hGg==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ ai: ^5.0.0-beta.12
+ zod: ^3.24.1 || ^v4
+
'@opentelemetry/api-logs@0.57.2':
resolution: {integrity: sha512-uIX52NnTM0iBh84MShlpouI7UKqkZ7MrUszTmaypHBu4r7NofznSnQRfJ+uUeDtQDj6w8eFGg5KBLDAwAPz1+A==}
engines: {node: '>=14'}
@@ -7527,6 +7537,11 @@ snapshots:
dependencies:
'@openpanel/sdk': 1.0.0
+ '@openrouter/ai-sdk-provider@1.0.0-beta.6(ai@5.0.0(zod@4.0.14))(zod@4.0.14)':
+ dependencies:
+ ai: 5.0.0(zod@4.0.14)
+ zod: 4.0.14
+
'@opentelemetry/api-logs@0.57.2':
dependencies:
'@opentelemetry/api': 1.9.0
diff --git a/src/ai/text/components/url-input-form.tsx b/src/ai/text/components/url-input-form.tsx
index 208b436..504d7de 100644
--- a/src/ai/text/components/url-input-form.tsx
+++ b/src/ai/text/components/url-input-form.tsx
@@ -164,6 +164,7 @@ export function UrlInputForm({
OpenAI GPT-4o
Google Gemini
DeepSeek
+ OpenRouter
diff --git a/src/ai/text/utils/web-content-analyzer-config.ts b/src/ai/text/utils/web-content-analyzer-config.ts
index 221e1b2..83b183c 100644
--- a/src/ai/text/utils/web-content-analyzer-config.ts
+++ b/src/ai/text/utils/web-content-analyzer-config.ts
@@ -117,6 +117,13 @@ export const webContentAnalyzerConfig = {
temperature: 0.1,
maxTokens: 2000,
},
+ openrouter: {
+ model: 'openrouter/horizon-beta',
+ // model: 'x-ai/grok-3-beta',
+ // model: 'openai/gpt-4o-mini',
+ temperature: 0.1,
+ maxTokens: 2000,
+ },
} as const;
/**
diff --git a/src/ai/text/utils/web-content-analyzer.ts b/src/ai/text/utils/web-content-analyzer.ts
index 72d2b7d..9e9e07b 100644
--- a/src/ai/text/utils/web-content-analyzer.ts
+++ b/src/ai/text/utils/web-content-analyzer.ts
@@ -97,9 +97,8 @@ export interface LoadingStatesProps {
// URL Validation Schema
export const urlSchema = z
- .string()
+ .url()
.min(1, 'URL is required')
- .url('Please enter a valid URL')
.refine(
(url) => url.startsWith('http://') || url.startsWith('https://'),
'URL must start with http:// or https://'
@@ -114,13 +113,13 @@ export const analysisResultsSchema = z.object({
pricing: z.string().default('Not specified'),
useCases: z.array(z.string()).default([]),
url: urlSchema,
- analyzedAt: z.string().datetime(),
+ analyzedAt: z.iso.datetime(),
});
// API Request Schema
export const analyzeContentRequestSchema = z.object({
url: urlSchema,
- modelProvider: z.enum(['openai', 'gemini', 'deepseek']),
+ modelProvider: z.enum(['openai', 'gemini', 'deepseek', 'openrouter']),
});
// API Response Schema
diff --git a/src/app/api/analyze-content/route.ts b/src/app/api/analyze-content/route.ts
index 094d365..91db24e 100644
--- a/src/app/api/analyze-content/route.ts
+++ b/src/app/api/analyze-content/route.ts
@@ -23,6 +23,7 @@ import { createDeepSeek } from '@ai-sdk/deepseek';
import { createGoogleGenerativeAI } from '@ai-sdk/google';
import { createOpenAI } from '@ai-sdk/openai';
import FirecrawlApp from '@mendable/firecrawl-js';
+import { createOpenRouter } from '@openrouter/ai-sdk-provider';
import { generateObject } from 'ai';
import { type NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';
@@ -230,6 +231,13 @@ async function analyzeContent(
temperature = webContentAnalyzerConfig.deepseek.temperature;
maxTokens = webContentAnalyzerConfig.deepseek.maxTokens;
break;
+ case 'openrouter':
+ model = createOpenRouter({
+ apiKey: process.env.OPENROUTER_API_KEY,
+ }).chat(webContentAnalyzerConfig.openrouter.model);
+ temperature = webContentAnalyzerConfig.openrouter.temperature;
+ maxTokens = webContentAnalyzerConfig.openrouter.maxTokens;
+ break;
default:
throw new WebContentAnalyzerError(
ErrorType.VALIDATION,