cloud: added openrouter integration with global configs

This commit is contained in:
DESKTOP-RTLN3BA\$punk 2026-04-15 23:46:29 -07:00
parent ff4e0f9b62
commit 4a51ccdc2c
26 changed files with 911 additions and 178 deletions

View file

@ -57,7 +57,7 @@ function buildModelFaq(model: AnonModel) {
},
{
question: `Is ${model.name} really free on SurfSense?`,
answer: `Yes! You can use ${model.name} completely free without login or sign-up. SurfSense gives you 1 million free tokens to use across any model, including ${model.name}.`,
answer: `Yes! You can use ${model.name} completely free without login or sign-up. SurfSense gives you 500,000 free tokens to use across any model, including ${model.name}.`,
},
{
question: `How do I use ${model.name} with no login?`,

View file

@ -107,12 +107,12 @@ const FAQ_ITEMS = [
{
question: "Can I use ChatGPT without login?",
answer:
"Yes. SurfSense lets you use ChatGPT without login or any sign-up. Just pick a model and start chatting. No email, no password, no account needed. You get 1 million free tokens to use across ChatGPT, Claude AI, Gemini, and other models.",
"Yes. SurfSense lets you use ChatGPT without login or any sign-up. Just pick a model and start chatting. No email, no password, no account needed. You get 500,000 free tokens to use across ChatGPT, Claude AI, Gemini, and other models.",
},
{
question: "Is ChatGPT really free on SurfSense?",
answer:
"Yes. SurfSense gives you free access to ChatGPT (GPT-4), Claude AI, Gemini, and other models without login. You get 1 million free tokens across any model with no sign-up required.",
"Yes. SurfSense gives you free access to ChatGPT (GPT-4), Claude AI, Gemini, and other models without login. You get 500,000 free tokens across any model with no sign-up required.",
},
{
question: "How do I use ChatGPT no login?",
@ -125,9 +125,9 @@ const FAQ_ITEMS = [
"SurfSense offers free access without login to models from OpenAI (GPT-4, GPT-4 Turbo), Anthropic (Claude 3, Claude free), Google (Gemini), DeepSeek, Mistral, Llama, and more. All available as a free ChatGPT alternative online with no login required.",
},
{
question: "What happens after I use 1 million free tokens?",
question: "What happens after I use my free tokens?",
answer:
"After your free tokens, create a free SurfSense account to unlock 5 million more. Premium model tokens can be purchased at $1 per million tokens. Non-premium models remain unlimited for registered users.",
"After your free tokens, create a free SurfSense account to unlock 3 million more premium tokens. Additional tokens can be purchased at $1 per million. Non-premium models remain unlimited for registered users.",
},
{
question: "Is Claude AI available without login?",
@ -203,7 +203,7 @@ export default async function FreeHubPage() {
No login required
</Badge>
<Badge variant="secondary" className="px-3 py-1.5 text-sm">
1M free tokens
500K free tokens
</Badge>
<Badge variant="secondary" className="px-3 py-1.5 text-sm">
{seoModels.length} AI models
@ -329,7 +329,7 @@ export default async function FreeHubPage() {
<section className="max-w-3xl mx-auto text-center">
<h2 className="text-2xl font-bold mb-3">Want More Features?</h2>
<p className="text-muted-foreground mb-6 leading-relaxed">
Create a free SurfSense account to unlock 5 million tokens, document uploads with
Create a free SurfSense account to unlock 3 million tokens, document uploads with
citations, team collaboration, and integrations with Slack, Google Drive, Notion, and
30+ more tools.
</p>

View file

@ -5,7 +5,7 @@ import { BreadcrumbNav } from "@/components/seo/breadcrumb-nav";
export const metadata: Metadata = {
title: "Pricing | SurfSense - Free AI Search Plans",
description:
"Explore SurfSense plans and pricing. Use ChatGPT, Claude AI, and any AI model free. Open source NotebookLM alternative for teams.",
"Explore SurfSense plans and pricing. Start free with 500 pages & 3M premium tokens. Use ChatGPT, Claude AI, and premium AI models. Pay-as-you-go tokens at $1 per million.",
alternates: {
canonical: "https://surfsense.com/pricing",
},

View file

@ -13,7 +13,7 @@ const changelogSource = loader({
source: changelog.toFumadocsSource(),
});
const BASE_URL = "https://surfsense.com";
const BASE_URL = "https://www.surfsense.com";
const BACKEND_URL = process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL || "http://localhost:8000";
async function getFreeModelSlugs(): Promise<string[]> {

View file

@ -1,38 +0,0 @@
---
title: "Why Enterprise Search Matters More Than Ever"
description: "As organizations generate more data across more tools, finding the right information at the right time has become a critical competitive advantage. Here's why enterprise search is no longer optional."
date: "2026-04-10"
image: "/og-image.png"
author: "SurfSense Team"
authorAvatar: "/logo.png"
tags: ["Enterprise Search", "Productivity", "Knowledge Management"]
---
## The Information Overload Problem
The average knowledge worker switches between **11 different applications** per day and spends nearly 20% of their time searching for information. That's an entire day each week lost to context-switching and hunting for answers buried in Slack threads, Google Docs, Notion pages, and email chains.
Enterprise search solves this by providing a **single, unified interface** to query across all your knowledge sources simultaneously.
## What Makes Modern Enterprise Search Different
Traditional enterprise search was little more than a keyword matcher slapped onto a file server. Modern solutions like SurfSense take a fundamentally different approach:
- **Semantic Understanding**: AI-powered search understands the *meaning* behind your query, not just the keywords
- **Federated Architecture**: Connect dozens of data sources without migrating data out of where it lives
- **Contextual Ranking**: Results are ranked by relevance to your role, recent activity, and team context
- **Real-time Indexing**: New content becomes searchable within minutes, not days
## The ROI of Getting Search Right
Organizations that invest in proper enterprise search see measurable improvements:
- **30% reduction** in time spent searching for information
- **25% faster** onboarding for new team members
- **40% fewer** duplicate documents and redundant work
## Getting Started
The best time to implement enterprise search was when your team hit 20 people. The second best time is now. Start by auditing which tools your team uses daily, then look for a solution that connects to all of them natively.
SurfSense connects to Slack, Google Drive, Notion, Confluence, GitHub, and dozens more — all with a single search bar.

View file

@ -222,7 +222,10 @@ export const FreeComposer: FC = () => {
<Tooltip>
<TooltipTrigger asChild>
<label htmlFor="free-web-search-toggle" className="flex items-center gap-1.5 cursor-pointer select-none rounded-md px-2 py-1 text-xs text-muted-foreground hover:text-foreground hover:bg-accent/50 transition-colors">
<label
htmlFor="free-web-search-toggle"
className="flex items-center gap-1.5 cursor-pointer select-none rounded-md px-2 py-1 text-xs text-muted-foreground hover:text-foreground hover:bg-accent/50 transition-colors"
>
<Globe className="size-3.5" />
<span className="hidden sm:inline">Web</span>
<Switch

View file

@ -40,16 +40,21 @@ export function FreeModelSelector({ className }: { className?: string }) {
[models, currentSlug]
);
const sortedModels = useMemo(
() => [...models].sort((a, b) => Number(a.is_premium) - Number(b.is_premium)),
[models]
);
const filteredModels = useMemo(() => {
if (!searchQuery.trim()) return models;
if (!searchQuery.trim()) return sortedModels;
const q = searchQuery.toLowerCase();
return models.filter(
return sortedModels.filter(
(m) =>
m.name.toLowerCase().includes(q) ||
m.model_name.toLowerCase().includes(q) ||
m.provider.toLowerCase().includes(q)
);
}, [models, searchQuery]);
}, [sortedModels, searchQuery]);
const handleSelect = useCallback(
(model: AnonModel) => {
@ -170,13 +175,20 @@ export function FreeModelSelector({ className }: { className?: string }) {
<div className="flex-1 min-w-0">
<div className="flex items-center gap-1.5">
<span className="font-medium text-sm truncate">{model.name}</span>
{model.is_premium && (
{model.is_premium ? (
<Badge
variant="secondary"
className="text-[9px] px-1 py-0 h-3.5 bg-purple-100 text-purple-700 dark:bg-purple-900/50 dark:text-purple-300 border-0"
>
Premium
</Badge>
) : (
<Badge
variant="secondary"
className="text-[9px] px-1 py-0 h-3.5 bg-emerald-100 text-emerald-700 dark:bg-emerald-900/50 dark:text-emerald-300 border-0"
>
Free
</Badge>
)}
</div>
<span className="text-xs text-muted-foreground truncate block">

View file

@ -40,7 +40,7 @@ export function QuotaWarningBanner({
</p>
<p className="text-xs text-red-600 dark:text-red-300">
You&apos;ve used all {limit.toLocaleString()} free tokens. Create a free account to
get 5 million tokens and access to all models.
get 3 million tokens and access to all models.
</p>
<Link
href="/register"

View file

@ -433,13 +433,31 @@ export function ModelSelector({
isGlobal && "is_auto_mode" in c && !!(c as Record<string, unknown>).is_auto_mode,
}));
const sortGlobalItems = (items: DisplayItem[]): DisplayItem[] =>
[...items].sort((a, b) => {
if (a.isAutoMode !== b.isAutoMode) return a.isAutoMode ? -1 : 1;
const aPremium = !!(a.config as Record<string, unknown>).is_premium;
const bPremium = !!(b.config as Record<string, unknown>).is_premium;
if (aPremium !== bPremium) return aPremium ? 1 : -1;
return 0;
});
switch (activeTab) {
case "llm":
return [...toItems(filteredLLMGlobal, true), ...toItems(filteredLLMUser, false)];
return [
...sortGlobalItems(toItems(filteredLLMGlobal, true)),
...toItems(filteredLLMUser, false),
];
case "image":
return [...toItems(filteredImageGlobal, true), ...toItems(filteredImageUser, false)];
return [
...sortGlobalItems(toItems(filteredImageGlobal, true)),
...toItems(filteredImageUser, false),
];
case "vision":
return [...toItems(filteredVisionGlobal, true), ...toItems(filteredVisionUser, false)];
return [
...sortGlobalItems(toItems(filteredVisionGlobal, true)),
...toItems(filteredVisionUser, false),
];
}
}, [
activeTab,
@ -859,14 +877,23 @@ export function ModelSelector({
Recommended
</Badge>
)}
{"is_premium" in config && (config as Record<string, unknown>).is_premium && (
{"is_premium" in config && (config as Record<string, unknown>).is_premium ? (
<Badge
variant="secondary"
className="text-[9px] px-1 py-0 h-3.5 bg-purple-100 text-purple-700 dark:bg-purple-900/50 dark:text-purple-300 border-0"
>
Premium
</Badge>
)}
) : "is_premium" in config &&
!(config as Record<string, unknown>).is_premium &&
!isAutoMode ? (
<Badge
variant="secondary"
className="text-[9px] px-1 py-0 h-3.5 bg-emerald-100 text-emerald-700 dark:bg-emerald-900/50 dark:text-emerald-300 border-0"
>
Free
</Badge>
) : null}
</div>
<div className="flex items-center gap-1.5 mt-0.5">
<span className="text-xs text-muted-foreground truncate">

View file

@ -12,10 +12,11 @@ const demoPlans = [
price: "0",
yearlyPrice: "0",
period: "",
billingText: "500 pages included",
billingText: "500 pages + 3M premium tokens included",
features: [
"Self Hostable",
"500 pages included to start",
"3 million premium tokens to start",
"Earn up to 3,000+ bonus pages for free",
"Includes access to OpenAI text, audio and image models",
"Realtime Collaborative Group Chats with teammates",
@ -30,11 +31,13 @@ const demoPlans = [
name: "PAY AS YOU GO",
price: "1",
yearlyPrice: "1",
period: "1,000 pages",
period: "pack",
billingText: "No subscription, buy only when you need more",
features: [
"Everything in Free",
"Buy 1,000-page packs at $1 each",
"Buy 1M premium token packs at $1 each",
"Use premium AI models like GPT-5.4, Claude Sonnet 4.6, Gemini 2.5 Pro & 100+ more via OpenRouter",
"Priority support on Discord",
],
description: "",
@ -77,7 +80,7 @@ interface FAQSection {
const faqData: FAQSection[] = [
{
title: "Pages & Billing",
title: "Pages & Document Billing",
items: [
{
question: 'What exactly is a "page" in SurfSense?',
@ -126,13 +129,38 @@ const faqData: FAQSection[] = [
},
],
},
{
title: "Premium Tokens",
items: [
{
question: 'What are "premium tokens"?',
answer:
"Premium tokens are the billing unit for using premium AI models like GPT-5.4, Claude Sonnet 4.6, and Gemini 2.5 Pro in SurfSense. Each AI request consumes tokens based on the length of your conversation. Non-premium models (such as free-tier models available without login) do not consume premium tokens.",
},
{
question: "How many premium tokens do I get for free?",
answer:
"Every registered SurfSense account starts with 3 million premium tokens at no cost. Anonymous users (no login) get 500,000 free tokens across all models. Once your free tokens are used up, you can purchase more at any time.",
},
{
question: "How does purchasing premium tokens work?",
answer:
"Just like pages, there's no subscription. You buy 1-million-token packs at $1 each whenever you need more. Purchased tokens are added to your account immediately. You can buy up to 100 packs at a time.",
},
{
question: "What happens if I run out of premium tokens?",
answer:
"When your premium token balance runs low (below 20%), you'll see a warning. Once you run out, premium model requests are paused until you purchase more tokens. You can always switch to non-premium models which don't consume premium tokens.",
},
],
},
{
title: "Self-Hosting",
items: [
{
question: "Can I self-host SurfSense with unlimited pages?",
question: "Can I self-host SurfSense with unlimited pages and tokens?",
answer:
"Yes! When self-hosting, you have full control over your page limits. The default self-hosted setup gives you effectively unlimited pages, so you can index as much data as your infrastructure supports.",
"Yes! When self-hosting, you have full control over your page and token limits. The default self-hosted setup gives you effectively unlimited pages and tokens, so you can index as much data and use as many AI queries as your infrastructure supports.",
},
],
},
@ -223,8 +251,8 @@ function PricingFAQ() {
Frequently Asked Questions
</h2>
<p className="mx-auto mt-4 max-w-2xl text-lg text-muted-foreground">
Everything you need to know about SurfSense pages and billing. Can&apos;t find what you
need? Reach out at{" "}
Everything you need to know about SurfSense pages, premium tokens, and billing. Can&apos;t
find what you need? Reach out at{" "}
<a href="mailto:rohan@surfsense.com" className="text-blue-500 underline">
rohan@surfsense.com
</a>
@ -308,7 +336,7 @@ function PricingBasic() {
<Pricing
plans={demoPlans}
title="SurfSense Pricing"
description="Start free with 500 pages and pay as you go."
description="Start free with 500 pages & 3M premium tokens. Pay as you go."
/>
<PricingFAQ />
</>

View file

@ -44,7 +44,7 @@ export function LoginGateProvider({ children }: { children: ReactNode }) {
<DialogHeader>
<DialogTitle>Create a free account to {feature}</DialogTitle>
<DialogDescription>
Get 5 million tokens, save chat history, upload documents, use all AI tools, and
Get 3 million tokens, save chat history, upload documents, use all AI tools, and
connect 30+ integrations.
</DialogDescription>
</DialogHeader>