Merge remote-tracking branch 'origin/main' into cloudflare
This commit is contained in:
commit
62eb4124be
@ -181,8 +181,9 @@ FAL_API_KEY=""
|
|||||||
FIREWORKS_API_KEY=""
|
FIREWORKS_API_KEY=""
|
||||||
OPENAI_API_KEY=""
|
OPENAI_API_KEY=""
|
||||||
REPLICATE_API_TOKEN=""
|
REPLICATE_API_TOKEN=""
|
||||||
GOOGLE_API_KEY=""
|
GOOGLE_GENERATIVE_AI_API_KEY=""
|
||||||
DEEPSEEK_API_KEY=""
|
DEEPSEEK_API_KEY=""
|
||||||
|
OPENROUTER_API_KEY=""
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Web Content Analyzer (Firecrawl)
|
# Web Content Analyzer (Firecrawl)
|
||||||
|
24
package.json
24
package.json
@ -25,13 +25,12 @@
|
|||||||
"knip": "knip"
|
"knip": "knip"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ai-sdk/deepseek": "^0.2.16",
|
"@ai-sdk/deepseek": "^1.0.0",
|
||||||
"@ai-sdk/fal": "^0.1.12",
|
"@ai-sdk/fal": "^1.0.0",
|
||||||
"@ai-sdk/fireworks": "^0.2.14",
|
"@ai-sdk/fireworks": "^1.0.0",
|
||||||
"@ai-sdk/google": "^1.2.22",
|
"@ai-sdk/google": "^2.0.0",
|
||||||
"@ai-sdk/google-vertex": "^2.2.24",
|
"@ai-sdk/openai": "^2.0.0",
|
||||||
"@ai-sdk/openai": "^1.1.13",
|
"@ai-sdk/replicate": "^1.0.0",
|
||||||
"@ai-sdk/replicate": "^0.2.8",
|
|
||||||
"@base-ui-components/react": "1.0.0-beta.0",
|
"@base-ui-components/react": "1.0.0-beta.0",
|
||||||
"@better-fetch/fetch": "^1.1.18",
|
"@better-fetch/fetch": "^1.1.18",
|
||||||
"@dnd-kit/core": "^6.3.1",
|
"@dnd-kit/core": "^6.3.1",
|
||||||
@ -43,6 +42,7 @@
|
|||||||
"@mendable/firecrawl-js": "^1.29.1",
|
"@mendable/firecrawl-js": "^1.29.1",
|
||||||
"@next/third-parties": "^15.3.0",
|
"@next/third-parties": "^15.3.0",
|
||||||
"@openpanel/nextjs": "^1.0.7",
|
"@openpanel/nextjs": "^1.0.7",
|
||||||
|
"@openrouter/ai-sdk-provider": "^1.0.0-beta.6",
|
||||||
"@orama/orama": "^3.1.4",
|
"@orama/orama": "^3.1.4",
|
||||||
"@orama/tokenizers": "^3.1.4",
|
"@orama/tokenizers": "^3.1.4",
|
||||||
"@radix-ui/react-accordion": "^1.2.3",
|
"@radix-ui/react-accordion": "^1.2.3",
|
||||||
@ -83,7 +83,7 @@
|
|||||||
"@vercel/analytics": "^1.5.0",
|
"@vercel/analytics": "^1.5.0",
|
||||||
"@vercel/speed-insights": "^1.2.0",
|
"@vercel/speed-insights": "^1.2.0",
|
||||||
"@widgetbot/react-embed": "^1.9.0",
|
"@widgetbot/react-embed": "^1.9.0",
|
||||||
"ai": "^4.1.45",
|
"ai": "^5.0.0",
|
||||||
"better-auth": "^1.1.19",
|
"better-auth": "^1.1.19",
|
||||||
"canvas-confetti": "^1.9.3",
|
"canvas-confetti": "^1.9.3",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
@ -98,9 +98,9 @@
|
|||||||
"drizzle-orm": "^0.39.3",
|
"drizzle-orm": "^0.39.3",
|
||||||
"embla-carousel-react": "^8.5.2",
|
"embla-carousel-react": "^8.5.2",
|
||||||
"framer-motion": "^12.4.7",
|
"framer-motion": "^12.4.7",
|
||||||
"fumadocs-core": "^15.5.3",
|
"fumadocs-core": "^15.6.7",
|
||||||
"fumadocs-mdx": "^11.6.8",
|
"fumadocs-mdx": "^11.7.3",
|
||||||
"fumadocs-ui": "^15.5.3",
|
"fumadocs-ui": "^15.6.7",
|
||||||
"inngest": "^3.40.1",
|
"inngest": "^3.40.1",
|
||||||
"input-otp": "^1.4.2",
|
"input-otp": "^1.4.2",
|
||||||
"lucide-react": "^0.483.0",
|
"lucide-react": "^0.483.0",
|
||||||
@ -133,7 +133,7 @@
|
|||||||
"use-intl": "^3.26.5",
|
"use-intl": "^3.26.5",
|
||||||
"use-media": "^1.5.0",
|
"use-media": "^1.5.0",
|
||||||
"vaul": "^1.1.2",
|
"vaul": "^1.1.2",
|
||||||
"zod": "^3.24.2",
|
"zod": "^4.0.14",
|
||||||
"zustand": "^5.0.3"
|
"zustand": "^5.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
959
pnpm-lock.yaml
generated
959
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,7 @@ const actionClient = createSafeActionClient();
|
|||||||
|
|
||||||
// Newsletter schema for validation
|
// Newsletter schema for validation
|
||||||
const newsletterSchema = z.object({
|
const newsletterSchema = z.object({
|
||||||
email: z.string().email({ message: 'Please enter a valid email address' }),
|
email: z.email({ error: 'Please enter a valid email address' }),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create a safe action to check if a user is subscribed to the newsletter
|
// Create a safe action to check if a user is subscribed to the newsletter
|
||||||
|
@ -18,10 +18,10 @@ const actionClient = createSafeActionClient();
|
|||||||
// Checkout schema for validation
|
// Checkout schema for validation
|
||||||
// metadata is optional, and may contain referral information if you need
|
// metadata is optional, and may contain referral information if you need
|
||||||
const checkoutSchema = z.object({
|
const checkoutSchema = z.object({
|
||||||
userId: z.string().min(1, { message: 'User ID is required' }),
|
userId: z.string().min(1, { error: 'User ID is required' }),
|
||||||
planId: z.string().min(1, { message: 'Plan ID is required' }),
|
planId: z.string().min(1, { error: 'Plan ID is required' }),
|
||||||
priceId: z.string().min(1, { message: 'Price ID is required' }),
|
priceId: z.string().min(1, { error: 'Price ID is required' }),
|
||||||
metadata: z.record(z.string()).optional(),
|
metadata: z.record(z.string(), z.string()).optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,10 +18,10 @@ const actionClient = createSafeActionClient();
|
|||||||
// Credit checkout schema for validation
|
// Credit checkout schema for validation
|
||||||
// metadata is optional, and may contain referral information if you need
|
// metadata is optional, and may contain referral information if you need
|
||||||
const creditCheckoutSchema = z.object({
|
const creditCheckoutSchema = z.object({
|
||||||
userId: z.string().min(1, { message: 'User ID is required' }),
|
userId: z.string().min(1, { error: 'User ID is required' }),
|
||||||
packageId: z.string().min(1, { message: 'Package ID is required' }),
|
packageId: z.string().min(1, { error: 'Package ID is required' }),
|
||||||
priceId: z.string().min(1, { message: 'Price ID is required' }),
|
priceId: z.string().min(1, { error: 'Price ID is required' }),
|
||||||
metadata: z.record(z.string()).optional(),
|
metadata: z.record(z.string(), z.string()).optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,10 +16,10 @@ const actionClient = createSafeActionClient();
|
|||||||
|
|
||||||
// Portal schema for validation
|
// Portal schema for validation
|
||||||
const portalSchema = z.object({
|
const portalSchema = z.object({
|
||||||
userId: z.string().min(1, { message: 'User ID is required' }),
|
userId: z.string().min(1, { error: 'User ID is required' }),
|
||||||
returnUrl: z
|
returnUrl: z
|
||||||
.string()
|
.string()
|
||||||
.url({ message: 'Return URL must be a valid URL' })
|
.url({ error: 'Return URL must be a valid URL' })
|
||||||
.optional(),
|
.optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ const actionClient = createSafeActionClient();
|
|||||||
|
|
||||||
// Input schema
|
// Input schema
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
userId: z.string().min(1, { message: 'User ID is required' }),
|
userId: z.string().min(1, { error: 'User ID is required' }),
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,6 +47,18 @@ export const getActiveSubscriptionAction = actionClient
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if Stripe environment variables are configured
|
||||||
|
const stripeSecretKey = process.env.STRIPE_SECRET_KEY;
|
||||||
|
const stripeWebhookSecret = process.env.STRIPE_WEBHOOK_SECRET;
|
||||||
|
|
||||||
|
if (!stripeSecretKey || !stripeWebhookSecret) {
|
||||||
|
console.log('Stripe environment variables not configured, return');
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: null, // No subscription = free plan
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Find the user's most recent active subscription
|
// Find the user's most recent active subscription
|
||||||
const subscriptions = await getSubscriptions({
|
const subscriptions = await getSubscriptions({
|
||||||
|
@ -14,7 +14,7 @@ const actionClient = createSafeActionClient();
|
|||||||
|
|
||||||
// Input schema
|
// Input schema
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
userId: z.string().min(1, { message: 'User ID is required' }),
|
userId: z.string().min(1, { error: 'User ID is required' }),
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,13 +17,13 @@ const actionClient = createSafeActionClient();
|
|||||||
const contactFormSchema = z.object({
|
const contactFormSchema = z.object({
|
||||||
name: z
|
name: z
|
||||||
.string()
|
.string()
|
||||||
.min(3, { message: 'Name must be at least 3 characters' })
|
.min(3, { error: 'Name must be at least 3 characters' })
|
||||||
.max(30, { message: 'Name must not exceed 30 characters' }),
|
.max(30, { error: 'Name must not exceed 30 characters' }),
|
||||||
email: z.string().email({ message: 'Please enter a valid email address' }),
|
email: z.email({ error: 'Please enter a valid email address' }),
|
||||||
message: z
|
message: z
|
||||||
.string()
|
.string()
|
||||||
.min(10, { message: 'Message must be at least 10 characters' })
|
.min(10, { error: 'Message must be at least 10 characters' })
|
||||||
.max(500, { message: 'Message must not exceed 500 characters' }),
|
.max(500, { error: 'Message must not exceed 500 characters' }),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create a safe action for contact form submission
|
// Create a safe action for contact form submission
|
||||||
|
@ -11,7 +11,7 @@ const actionClient = createSafeActionClient();
|
|||||||
|
|
||||||
// Newsletter schema for validation
|
// Newsletter schema for validation
|
||||||
const newsletterSchema = z.object({
|
const newsletterSchema = z.object({
|
||||||
email: z.string().email({ message: 'Please enter a valid email address' }),
|
email: z.email({ error: 'Please enter a valid email address' }),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create a safe action for newsletter subscription
|
// Create a safe action for newsletter subscription
|
||||||
|
@ -10,7 +10,7 @@ const actionClient = createSafeActionClient();
|
|||||||
|
|
||||||
// Newsletter schema for validation
|
// Newsletter schema for validation
|
||||||
const newsletterSchema = z.object({
|
const newsletterSchema = z.object({
|
||||||
email: z.string().email({ message: 'Please enter a valid email address' }),
|
email: z.email({ error: 'Please enter a valid email address' }),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create a safe action for newsletter unsubscription
|
// Create a safe action for newsletter unsubscription
|
||||||
|
@ -9,7 +9,7 @@ const actionClient = createSafeActionClient();
|
|||||||
|
|
||||||
// Captcha validation schema
|
// Captcha validation schema
|
||||||
const captchaSchema = z.object({
|
const captchaSchema = z.object({
|
||||||
captchaToken: z.string().min(1, { message: 'Captcha token is required' }),
|
captchaToken: z.string().min(1, { error: 'Captcha token is required' }),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create a safe action for captcha validation
|
// Create a safe action for captcha validation
|
||||||
|
@ -61,7 +61,6 @@ export function ImagePlayground({
|
|||||||
|
|
||||||
const providerToModel = {
|
const providerToModel = {
|
||||||
replicate: selectedModels.replicate,
|
replicate: selectedModels.replicate,
|
||||||
// vertex: selectedModels.vertex,
|
|
||||||
openai: selectedModels.openai,
|
openai: selectedModels.openai,
|
||||||
fireworks: selectedModels.fireworks,
|
fireworks: selectedModels.fireworks,
|
||||||
fal: selectedModels.fal,
|
fal: selectedModels.fal,
|
||||||
|
@ -15,7 +15,6 @@ import {
|
|||||||
FireworksIcon,
|
FireworksIcon,
|
||||||
OpenAIIcon,
|
OpenAIIcon,
|
||||||
ReplicateIcon,
|
ReplicateIcon,
|
||||||
// VertexIcon,
|
|
||||||
falAILogo,
|
falAILogo,
|
||||||
} from '../lib/logos';
|
} from '../lib/logos';
|
||||||
import type { ProviderKey } from '../lib/provider-config';
|
import type { ProviderKey } from '../lib/provider-config';
|
||||||
@ -40,7 +39,6 @@ interface ModelSelectProps {
|
|||||||
const PROVIDER_ICONS = {
|
const PROVIDER_ICONS = {
|
||||||
openai: OpenAIIcon,
|
openai: OpenAIIcon,
|
||||||
replicate: ReplicateIcon,
|
replicate: ReplicateIcon,
|
||||||
// vertex: VertexIcon,
|
|
||||||
fireworks: FireworksIcon,
|
fireworks: FireworksIcon,
|
||||||
fal: falAILogo,
|
fal: falAILogo,
|
||||||
} as const;
|
} as const;
|
||||||
@ -48,7 +46,6 @@ const PROVIDER_ICONS = {
|
|||||||
const PROVIDER_LINKS = {
|
const PROVIDER_LINKS = {
|
||||||
openai: 'openai',
|
openai: 'openai',
|
||||||
replicate: 'replicate',
|
replicate: 'replicate',
|
||||||
// vertex: 'google-vertex',
|
|
||||||
fireworks: 'fireworks',
|
fireworks: 'fireworks',
|
||||||
fal: 'fal',
|
fal: 'fal',
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -62,55 +62,6 @@ export const ReplicateIcon = ({ size = 16 }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const VertexIcon = ({ size = 16 }) => {
|
|
||||||
return (
|
|
||||||
<svg
|
|
||||||
height={size}
|
|
||||||
width={size}
|
|
||||||
viewBox="0 0 512 512"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
style={{ color: 'currentcolor' }}
|
|
||||||
>
|
|
||||||
<g transform="scale(0.8) translate(65,65)">
|
|
||||||
<path
|
|
||||||
d="M128,249c-8.8,0-16-7.2-16-16v-105c0-8.8,7.2-16,16-16s16,7.2,16,16v105c0,8.8-7.2,16-16,16Z"
|
|
||||||
fill="white"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M256,464c-3,0-6-.8-8.6-2.5l-176-112c-7.5-4.7-9.7-14.6-4.9-22.1,4.8-7.5,14.6-9.6,22.1-4.9l167.4,106.5,167.4-106.5c7.5-4.7,17.3-2.5,22.1,4.9,4.7,7.5,2.5,17.3-4.9,22.1l-176,112c-2.6,1.7-5.6,2.5-8.6,2.5h0Z"
|
|
||||||
fill="white"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M256,394c-8.8,0-16-7.2-16-16v-73.1c0-8.8,7.2-16,16-16s16,7.2,16,16v73.1c0,8.8-7.2,16-16,16Z"
|
|
||||||
fill="white"
|
|
||||||
/>
|
|
||||||
<circle cx="128" cy="64" r="16" fill="white" />
|
|
||||||
<circle cx="128" cy="297" r="16" fill="white" />
|
|
||||||
<path
|
|
||||||
d="M384.2,314c-8.8,0-16-7.1-16-16l-.2-106c0-8.8,7.1-16,16-16h0c8.8,0,16,7.1,16,16l.2,106c0,8.8-7.1,16-16,16h0Z"
|
|
||||||
fill="white"
|
|
||||||
/>
|
|
||||||
<circle cx="384" cy="64" r="16" fill="white" />
|
|
||||||
<circle cx="384" cy="128" r="16" fill="white" />
|
|
||||||
<path
|
|
||||||
d="M320,225c-8.8,0-16-7.2-16-16v-103c0-8.8,7.2-16,16-16s16,7.2,16,16v103c0,8.8-7.2,16-16,16Z"
|
|
||||||
fill="white"
|
|
||||||
/>
|
|
||||||
<circle cx="256" cy="177" r="16" fill="white" />
|
|
||||||
<circle cx="256" cy="241" r="16" fill="white" />
|
|
||||||
<circle cx="320" cy="273" r="16" fill="white" />
|
|
||||||
<circle cx="320" cy="337" r="16" fill="white" />
|
|
||||||
<path
|
|
||||||
d="M192,225c-8.8,0-16-7.2-16-16v-103c0-8.8,7.2-16,16-16s16,7.2,16,16v103c0,8.8-7.2,16-16,16Z"
|
|
||||||
fill="white"
|
|
||||||
/>
|
|
||||||
<circle cx="192" cy="273" r="16" fill="white" />
|
|
||||||
<circle cx="192" cy="337" r="16" fill="white" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const falAILogo = ({ size = 16 }: { size: number }) => {
|
export const falAILogo = ({ size = 16 }: { size: number }) => {
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
|
@ -1,9 +1,4 @@
|
|||||||
export type ProviderKey =
|
export type ProviderKey = 'replicate' | 'openai' | 'fireworks' | 'fal';
|
||||||
| 'replicate'
|
|
||||||
// | 'vertex'
|
|
||||||
| 'openai'
|
|
||||||
| 'fireworks'
|
|
||||||
| 'fal';
|
|
||||||
export type ModelMode = 'performance' | 'quality';
|
export type ModelMode = 'performance' | 'quality';
|
||||||
|
|
||||||
export const PROVIDERS: Record<
|
export const PROVIDERS: Record<
|
||||||
@ -37,12 +32,6 @@ export const PROVIDERS: Record<
|
|||||||
'stability-ai/stable-diffusion-3.5-large-turbo',
|
'stability-ai/stable-diffusion-3.5-large-turbo',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
// vertex: {
|
|
||||||
// displayName: 'Vertex AI',
|
|
||||||
// iconPath: '/provider-icons/vertex.svg',
|
|
||||||
// color: 'from-green-500 to-emerald-500',
|
|
||||||
// models: ['imagen-3.0-generate-001', 'imagen-3.0-fast-generate-001'],
|
|
||||||
// },
|
|
||||||
// https://ai-sdk.dev/providers/ai-sdk-providers/openai#image-models
|
// https://ai-sdk.dev/providers/ai-sdk-providers/openai#image-models
|
||||||
openai: {
|
openai: {
|
||||||
displayName: 'OpenAI',
|
displayName: 'OpenAI',
|
||||||
@ -92,14 +81,12 @@ export const PROVIDERS: Record<
|
|||||||
export const MODEL_CONFIGS: Record<ModelMode, Record<ProviderKey, string>> = {
|
export const MODEL_CONFIGS: Record<ModelMode, Record<ProviderKey, string>> = {
|
||||||
performance: {
|
performance: {
|
||||||
replicate: 'black-forest-labs/flux-1.1-pro',
|
replicate: 'black-forest-labs/flux-1.1-pro',
|
||||||
// vertex: 'imagen-3.0-fast-generate-001',
|
|
||||||
openai: 'dall-e-3',
|
openai: 'dall-e-3',
|
||||||
fireworks: 'accounts/fireworks/models/flux-1-schnell-fp8',
|
fireworks: 'accounts/fireworks/models/flux-1-schnell-fp8',
|
||||||
fal: 'fal-ai/flux/dev',
|
fal: 'fal-ai/flux/dev',
|
||||||
},
|
},
|
||||||
quality: {
|
quality: {
|
||||||
replicate: 'stability-ai/stable-diffusion-3.5-large',
|
replicate: 'stability-ai/stable-diffusion-3.5-large',
|
||||||
// vertex: 'imagen-3.0-generate-001',
|
|
||||||
openai: 'dall-e-3',
|
openai: 'dall-e-3',
|
||||||
fireworks: 'accounts/fireworks/models/flux-1-dev-fp8',
|
fireworks: 'accounts/fireworks/models/flux-1-dev-fp8',
|
||||||
fal: 'fal-ai/flux-pro/v1.1-ultra',
|
fal: 'fal-ai/flux-pro/v1.1-ultra',
|
||||||
@ -108,7 +95,6 @@ export const MODEL_CONFIGS: Record<ModelMode, Record<ProviderKey, string>> = {
|
|||||||
|
|
||||||
export const PROVIDER_ORDER: ProviderKey[] = [
|
export const PROVIDER_ORDER: ProviderKey[] = [
|
||||||
'replicate',
|
'replicate',
|
||||||
// 'vertex',
|
|
||||||
'openai',
|
'openai',
|
||||||
'fireworks',
|
'fireworks',
|
||||||
'fal',
|
'fal',
|
||||||
|
@ -40,7 +40,7 @@ import { useDebounce } from '../utils/performance';
|
|||||||
|
|
||||||
// Form schema for URL input
|
// Form schema for URL input
|
||||||
const urlFormSchema = z.object({
|
const urlFormSchema = z.object({
|
||||||
url: z.string().url().optional(), // Allow empty string for initial state
|
url: z.url().optional(), // Allow empty string for initial state
|
||||||
});
|
});
|
||||||
|
|
||||||
type UrlFormData = z.infer<typeof urlFormSchema>;
|
type UrlFormData = z.infer<typeof urlFormSchema>;
|
||||||
@ -164,6 +164,7 @@ export function UrlInputForm({
|
|||||||
<SelectItem value="openai">OpenAI GPT-4o</SelectItem>
|
<SelectItem value="openai">OpenAI GPT-4o</SelectItem>
|
||||||
<SelectItem value="gemini">Google Gemini</SelectItem>
|
<SelectItem value="gemini">Google Gemini</SelectItem>
|
||||||
<SelectItem value="deepseek">DeepSeek</SelectItem>
|
<SelectItem value="deepseek">DeepSeek</SelectItem>
|
||||||
|
<SelectItem value="openrouter">OpenRouter</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
@ -117,6 +117,13 @@ export const webContentAnalyzerConfig = {
|
|||||||
temperature: 0.1,
|
temperature: 0.1,
|
||||||
maxTokens: 2000,
|
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;
|
} as const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -97,9 +97,8 @@ export interface LoadingStatesProps {
|
|||||||
|
|
||||||
// URL Validation Schema
|
// URL Validation Schema
|
||||||
export const urlSchema = z
|
export const urlSchema = z
|
||||||
.string()
|
.url()
|
||||||
.min(1, 'URL is required')
|
.min(1, 'URL is required')
|
||||||
.url('Please enter a valid URL')
|
|
||||||
.refine(
|
.refine(
|
||||||
(url) => url.startsWith('http://') || url.startsWith('https://'),
|
(url) => url.startsWith('http://') || url.startsWith('https://'),
|
||||||
'URL must start with http:// or https://'
|
'URL must start with http:// or https://'
|
||||||
@ -114,13 +113,13 @@ export const analysisResultsSchema = z.object({
|
|||||||
pricing: z.string().default('Not specified'),
|
pricing: z.string().default('Not specified'),
|
||||||
useCases: z.array(z.string()).default([]),
|
useCases: z.array(z.string()).default([]),
|
||||||
url: urlSchema,
|
url: urlSchema,
|
||||||
analyzedAt: z.string().datetime(),
|
analyzedAt: z.iso.datetime(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// API Request Schema
|
// API Request Schema
|
||||||
export const analyzeContentRequestSchema = z.object({
|
export const analyzeContentRequestSchema = z.object({
|
||||||
url: urlSchema,
|
url: urlSchema,
|
||||||
modelProvider: z.enum(['openai', 'gemini', 'deepseek']),
|
modelProvider: z.enum(['openai', 'gemini', 'deepseek', 'openrouter']),
|
||||||
});
|
});
|
||||||
|
|
||||||
// API Response Schema
|
// API Response Schema
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
import { UpdateAvatarCard } from '@/components/settings/profile/update-avatar-card';
|
import { UpdateAvatarCard } from '@/components/settings/profile/update-avatar-card';
|
||||||
import { UpdateNameCard } from '@/components/settings/profile/update-name-card';
|
import { UpdateNameCard } from '@/components/settings/profile/update-name-card';
|
||||||
|
import { websiteConfig } from '@/config/website';
|
||||||
|
|
||||||
export default function ProfilePage() {
|
export default function ProfilePage() {
|
||||||
|
const enableUpdateAvatar = websiteConfig.features.enableUpdateAvatar;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-8">
|
<div className="flex flex-col gap-8">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
{enableUpdateAvatar && (
|
||||||
<UpdateAvatarCard />
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||||
</div>
|
<UpdateAvatarCard />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||||
<UpdateNameCard />
|
<UpdateNameCard />
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { ActiveThemeProvider } from '@/components/layout/active-theme-provider';
|
import { ActiveThemeProvider } from '@/components/layout/active-theme-provider';
|
||||||
|
import { CreditsProvider } from '@/components/layout/credits-provider';
|
||||||
import { PaymentProvider } from '@/components/layout/payment-provider';
|
import { PaymentProvider } from '@/components/layout/payment-provider';
|
||||||
import { TooltipProvider } from '@/components/ui/tooltip';
|
import { TooltipProvider } from '@/components/ui/tooltip';
|
||||||
import { websiteConfig } from '@/config/website';
|
import { websiteConfig } from '@/config/website';
|
||||||
import { CreditsProvider } from '@/providers/credits-provider';
|
|
||||||
import type { Translations } from 'fumadocs-ui/i18n';
|
import type { Translations } from 'fumadocs-ui/i18n';
|
||||||
import { RootProvider } from 'fumadocs-ui/provider';
|
import { RootProvider } from 'fumadocs-ui/provider';
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
|
@ -23,6 +23,7 @@ import { createDeepSeek } from '@ai-sdk/deepseek';
|
|||||||
import { createGoogleGenerativeAI } from '@ai-sdk/google';
|
import { createGoogleGenerativeAI } from '@ai-sdk/google';
|
||||||
import { createOpenAI } from '@ai-sdk/openai';
|
import { createOpenAI } from '@ai-sdk/openai';
|
||||||
import FirecrawlApp from '@mendable/firecrawl-js';
|
import FirecrawlApp from '@mendable/firecrawl-js';
|
||||||
|
import { createOpenRouter } from '@openrouter/ai-sdk-provider';
|
||||||
import { generateObject } from 'ai';
|
import { generateObject } from 'ai';
|
||||||
import { type NextRequest, NextResponse } from 'next/server';
|
import { type NextRequest, NextResponse } from 'next/server';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
@ -218,7 +219,7 @@ async function analyzeContent(
|
|||||||
break;
|
break;
|
||||||
case 'gemini':
|
case 'gemini':
|
||||||
model = createGoogleGenerativeAI({
|
model = createGoogleGenerativeAI({
|
||||||
apiKey: process.env.GOOGLE_API_KEY,
|
apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY,
|
||||||
}).chat(webContentAnalyzerConfig.gemini.model);
|
}).chat(webContentAnalyzerConfig.gemini.model);
|
||||||
temperature = webContentAnalyzerConfig.gemini.temperature;
|
temperature = webContentAnalyzerConfig.gemini.temperature;
|
||||||
maxTokens = webContentAnalyzerConfig.gemini.maxTokens;
|
maxTokens = webContentAnalyzerConfig.gemini.maxTokens;
|
||||||
@ -230,6 +231,13 @@ async function analyzeContent(
|
|||||||
temperature = webContentAnalyzerConfig.deepseek.temperature;
|
temperature = webContentAnalyzerConfig.deepseek.temperature;
|
||||||
maxTokens = webContentAnalyzerConfig.deepseek.maxTokens;
|
maxTokens = webContentAnalyzerConfig.deepseek.maxTokens;
|
||||||
break;
|
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:
|
default:
|
||||||
throw new WebContentAnalyzerError(
|
throw new WebContentAnalyzerError(
|
||||||
ErrorType.VALIDATION,
|
ErrorType.VALIDATION,
|
||||||
@ -254,7 +262,7 @@ async function analyzeContent(
|
|||||||
- Ensure the title and description are meaningful and based on the actual content
|
- Ensure the title and description are meaningful and based on the actual content
|
||||||
`,
|
`,
|
||||||
temperature,
|
temperature,
|
||||||
maxTokens,
|
maxOutputTokens: maxTokens,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -336,7 +344,7 @@ export async function POST(req: NextRequest) {
|
|||||||
if (!urlValidation.success) {
|
if (!urlValidation.success) {
|
||||||
const urlError = new WebContentAnalyzerError(
|
const urlError = new WebContentAnalyzerError(
|
||||||
ErrorType.VALIDATION,
|
ErrorType.VALIDATION,
|
||||||
urlValidation.error.errors[0]?.message || 'Invalid URL',
|
urlValidation.error.issues[0]?.message || 'Invalid URL',
|
||||||
'Please enter a valid URL starting with http:// or https://',
|
'Please enter a valid URL starting with http:// or https://',
|
||||||
ErrorSeverity.MEDIUM,
|
ErrorSeverity.MEDIUM,
|
||||||
false
|
false
|
||||||
|
@ -32,7 +32,7 @@ export const ForgotPasswordForm = ({ className }: { className?: string }) => {
|
|||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
|
|
||||||
const ForgotPasswordSchema = z.object({
|
const ForgotPasswordSchema = z.object({
|
||||||
email: z.string().email({
|
email: z.email({
|
||||||
message: t('emailRequired'),
|
message: t('emailRequired'),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
@ -69,7 +69,7 @@ export const LoginForm = ({
|
|||||||
: z.string().optional();
|
: z.string().optional();
|
||||||
|
|
||||||
const LoginSchema = z.object({
|
const LoginSchema = z.object({
|
||||||
email: z.string().email({
|
email: z.email({
|
||||||
message: t('emailRequired'),
|
message: t('emailRequired'),
|
||||||
}),
|
}),
|
||||||
password: z.string().min(1, {
|
password: z.string().min(1, {
|
||||||
|
@ -64,7 +64,7 @@ export const RegisterForm = ({
|
|||||||
: z.string().optional();
|
: z.string().optional();
|
||||||
|
|
||||||
const RegisterSchema = z.object({
|
const RegisterSchema = z.object({
|
||||||
email: z.string().email({
|
email: z.email({
|
||||||
message: t('emailRequired'),
|
message: t('emailRequired'),
|
||||||
}),
|
}),
|
||||||
password: z.string().min(1, {
|
password: z.string().min(1, {
|
||||||
|
@ -40,7 +40,7 @@ export function ContactFormCard() {
|
|||||||
// Create a schema for contact form validation
|
// Create a schema for contact form validation
|
||||||
const formSchema = z.object({
|
const formSchema = z.object({
|
||||||
name: z.string().min(3, t('nameMinLength')).max(30, t('nameMaxLength')),
|
name: z.string().min(3, t('nameMinLength')).max(30, t('nameMaxLength')),
|
||||||
email: z.string().email(t('emailValidation')),
|
email: z.email(t('emailValidation')),
|
||||||
message: z
|
message: z
|
||||||
.string()
|
.string()
|
||||||
.min(10, t('messageMinLength'))
|
.min(10, t('messageMinLength'))
|
||||||
|
@ -29,7 +29,7 @@ export function NewsletterForm() {
|
|||||||
|
|
||||||
// newsletter schema
|
// newsletter schema
|
||||||
const NewsletterFormSchema = z.object({
|
const NewsletterFormSchema = z.object({
|
||||||
email: z.string().email({
|
email: z.email({
|
||||||
message: t('emailValidation'),
|
message: t('emailValidation'),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
@ -38,7 +38,7 @@ export function WaitlistFormCard() {
|
|||||||
|
|
||||||
// Create a schema for waitlist form validation
|
// Create a schema for waitlist form validation
|
||||||
const formSchema = z.object({
|
const formSchema = z.object({
|
||||||
email: z.string().email({ message: t('emailValidation') }),
|
email: z.email({ message: t('emailValidation') }),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initialize the form
|
// Initialize the form
|
||||||
|
@ -36,6 +36,7 @@ export const websiteConfig: WebsiteConfig = {
|
|||||||
enableDiscordWidget: false,
|
enableDiscordWidget: false,
|
||||||
enableCrispChat: process.env.NEXT_PUBLIC_DEMO_WEBSITE === 'true',
|
enableCrispChat: process.env.NEXT_PUBLIC_DEMO_WEBSITE === 'true',
|
||||||
enableUpgradeCard: true,
|
enableUpgradeCard: true,
|
||||||
|
enableUpdateAvatar: true,
|
||||||
enableAffonsoAffiliate: false,
|
enableAffonsoAffiliate: false,
|
||||||
enablePromotekitAffiliate: false,
|
enablePromotekitAffiliate: false,
|
||||||
enableDatafastRevenueTrack: false,
|
enableDatafastRevenueTrack: false,
|
||||||
|
1
src/types/index.d.ts
vendored
1
src/types/index.d.ts
vendored
@ -71,6 +71,7 @@ export interface FeaturesConfig {
|
|||||||
enableDiscordWidget?: boolean; // Whether to enable the discord widget, deprecated
|
enableDiscordWidget?: boolean; // Whether to enable the discord widget, deprecated
|
||||||
enableCrispChat?: boolean; // Whether to enable the crisp chat
|
enableCrispChat?: boolean; // Whether to enable the crisp chat
|
||||||
enableUpgradeCard?: boolean; // Whether to enable the upgrade card in the sidebar
|
enableUpgradeCard?: boolean; // Whether to enable the upgrade card in the sidebar
|
||||||
|
enableUpdateAvatar?: boolean; // Whether to enable the update avatar in settings
|
||||||
enableAffonsoAffiliate?: boolean; // Whether to enable affonso affiliate
|
enableAffonsoAffiliate?: boolean; // Whether to enable affonso affiliate
|
||||||
enablePromotekitAffiliate?: boolean; // Whether to enable promotekit affiliate
|
enablePromotekitAffiliate?: boolean; // Whether to enable promotekit affiliate
|
||||||
enableDatafastRevenueTrack?: boolean; // Whether to enable datafast revenue tracking
|
enableDatafastRevenueTrack?: boolean; // Whether to enable datafast revenue tracking
|
||||||
|
Loading…
Reference in New Issue
Block a user