Compare commits
10 Commits
186bd3c2cc
...
d468ecca74
| Author | SHA1 | Date | |
|---|---|---|---|
| d468ecca74 | |||
|
|
15d5ac5a61 | ||
|
|
706f53f3ed | ||
|
|
8247f9b4ea | ||
|
|
527e46453d | ||
|
|
0289fc44df | ||
|
|
690fd9fc79 | ||
|
|
74d4d8d5a0 | ||
|
|
fba1ccb0ef | ||
|
|
f8ce4bd871 |
29
.env.example
29
.env.example
@ -1,5 +1,28 @@
|
|||||||
ANTHROPIC_API_KEY=sk-ant-api****
|
# Strictly Server side Env variables
|
||||||
|
XAI_API_KEY=
|
||||||
|
UPSTASH_REDIS_REST_URL=
|
||||||
|
UPSTASH_REDIS_REST_TOKEN=
|
||||||
|
AVIATION_STACK_API_KEY=
|
||||||
|
SANDBOX_TEMPLATE_ID=
|
||||||
|
TMDB_API_KEY=
|
||||||
|
YT_ENDPOINT=
|
||||||
|
EXA_API_KEY=
|
||||||
|
TRIPADVISOR_API_KEY=
|
||||||
|
BLOB_READ_WRITE_TOKEN=
|
||||||
|
ELEVENLABS_API_KEY=
|
||||||
|
AZURE_TRANSLATOR_LOCATION=
|
||||||
|
AZURE_TRANSLATOR_KEY=
|
||||||
|
AZURE_RESOURCE_NAME=
|
||||||
|
AZURE_API_KEY=
|
||||||
|
MAPBOX_ACCESS_TOKEN=
|
||||||
|
FIRECRAWL_API_KEY=
|
||||||
TAVILY_API_KEY=tvly-****
|
TAVILY_API_KEY=tvly-****
|
||||||
GROQ_API_KEY=gsk_****
|
OPENWEATHER_API_KEY=
|
||||||
OPENWEATHER_API_KEY=***
|
|
||||||
E2B_API_KEY=e2b_****
|
E2B_API_KEY=e2b_****
|
||||||
|
GOOGLE_MAPS_API_KEY=
|
||||||
|
|
||||||
|
# Client side Env variables
|
||||||
|
NEXT_PUBLIC_POSTHOG_KEY=
|
||||||
|
NEXT_PUBLIC_POSTHOG_HOST=
|
||||||
|
NEXT_PUBLIC_MAPBOX_TOKEN=
|
||||||
|
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { serverEnv } from '@/env/server';
|
||||||
import { del, list, ListBlobResult } from '@vercel/blob';
|
import { del, list, ListBlobResult } from '@vercel/blob';
|
||||||
import { NextRequest, NextResponse } from 'next/server';
|
import { NextRequest, NextResponse } from 'next/server';
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import { NextResponse } from 'next/server';
|
import { NextResponse } from 'next/server';
|
||||||
import { generateObject } from 'ai';
|
import { generateObject } from 'ai';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { geolocation } from '@vercel/functions';
|
|
||||||
import { xai } from '@ai-sdk/xai';
|
import { xai } from '@ai-sdk/xai';
|
||||||
|
|
||||||
export interface TrendingQuery {
|
export interface TrendingQuery {
|
||||||
@ -16,7 +15,7 @@ interface RedditPost {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchGoogleTrends(countryCode: string = 'US'): Promise<TrendingQuery[]> {
|
async function fetchGoogleTrends(): Promise<TrendingQuery[]> {
|
||||||
const fetchTrends = async (geo: string): Promise<TrendingQuery[]> => {
|
const fetchTrends = async (geo: string): Promise<TrendingQuery[]> => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`https://trends.google.com/trends/trendingsearches/daily/rss?geo=${geo}`, {
|
const response = await fetch(`https://trends.google.com/trends/trendingsearches/daily/rss?geo=${geo}`, {
|
||||||
@ -62,7 +61,7 @@ async function fetchGoogleTrends(countryCode: string = 'US'): Promise<TrendingQu
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const trends = await fetchTrends(countryCode);
|
const trends = await fetchTrends("US");
|
||||||
|
|
||||||
return [ ...trends];
|
return [ ...trends];
|
||||||
}
|
}
|
||||||
@ -95,11 +94,11 @@ async function fetchRedditQuestions(): Promise<TrendingQuery[]> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchFromMultipleSources(countryCode: string) {
|
async function fetchFromMultipleSources() {
|
||||||
const [googleTrends,
|
const [googleTrends,
|
||||||
// redditQuestions
|
// redditQuestions
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
fetchGoogleTrends(countryCode),
|
fetchGoogleTrends(),
|
||||||
// fetchRedditQuestions(),
|
// fetchRedditQuestions(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -112,11 +111,11 @@ async function fetchFromMultipleSources(countryCode: string) {
|
|||||||
|
|
||||||
export async function GET(req: Request) {
|
export async function GET(req: Request) {
|
||||||
try {
|
try {
|
||||||
const countryCode = geolocation(req).countryRegion ?? 'US';
|
const trends = await fetchFromMultipleSources();
|
||||||
const trends = await fetchFromMultipleSources(countryCode);
|
|
||||||
|
|
||||||
if (trends.length === 0) {
|
if (trends.length === 0) {
|
||||||
// Fallback queries if both sources fail
|
// Fallback queries if both sources fail
|
||||||
|
console.error('Both sources failed to fetch trends, returning fallback queries');
|
||||||
return NextResponse.json([
|
return NextResponse.json([
|
||||||
{
|
{
|
||||||
icon: 'sparkles',
|
icon: 'sparkles',
|
||||||
|
|||||||
@ -1,16 +1,7 @@
|
|||||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Instrument+Serif:wght@400&display=swap');
|
|
||||||
@tailwind base;
|
@tailwind base;
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
:root {
|
|
||||||
--font-serif: "Instrument Serif", serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: var(--font-sans), sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.homeBtn {
|
.homeBtn {
|
||||||
box-shadow: rgba(0, 0, 0, 0.4) 0px 2px 4px,
|
box-shadow: rgba(0, 0, 0, 0.4) 0px 2px 4px,
|
||||||
rgba(0, 0, 0, 0.3) 0px 7px 13px -3px, rgba(0, 0, 0, 0.2) 0px -3px 0px inset,
|
rgba(0, 0, 0, 0.3) 0px 7px 13px -3px, rgba(0, 0, 0, 0.2) 0px -3px 0px inset,
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
import "./globals.css";
|
import { Analytics } from "@vercel/analytics/react";
|
||||||
|
import { GeistSans } from 'geist/font/sans';
|
||||||
import 'katex/dist/katex.min.css';
|
import 'katex/dist/katex.min.css';
|
||||||
import 'mapbox-gl/dist/mapbox-gl.css';
|
import 'mapbox-gl/dist/mapbox-gl.css';
|
||||||
import { Metadata, Viewport } from "next";
|
import { Metadata, Viewport } from "next";
|
||||||
import { Toaster } from "sonner";
|
|
||||||
import { Instrument_Serif } from 'next/font/google';
|
import { Instrument_Serif } from 'next/font/google';
|
||||||
import { Analytics } from "@vercel/analytics/react";
|
import { NuqsAdapter } from 'nuqs/adapters/next/app';
|
||||||
import { Providers } from './providers'
|
import { Toaster } from "sonner";
|
||||||
import { GeistSans } from 'geist/font/sans';
|
import "./globals.css";
|
||||||
|
import { Providers } from './providers';
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
metadataBase: new URL("https://mplx.run"),
|
metadataBase: new URL("https://mplx.run"),
|
||||||
@ -43,7 +44,11 @@ export const viewport: Viewport = {
|
|||||||
const instrumentSerif = Instrument_Serif({
|
const instrumentSerif = Instrument_Serif({
|
||||||
weight: "400",
|
weight: "400",
|
||||||
subsets: ["latin"],
|
subsets: ["latin"],
|
||||||
variable: "--font-serif"
|
style: ['normal', 'italic'],
|
||||||
|
variable: "--font-serif",
|
||||||
|
preload: true,
|
||||||
|
display: 'swap',
|
||||||
|
fallback: ['sans-serif'],
|
||||||
})
|
})
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
@ -53,11 +58,13 @@ export default function RootLayout({
|
|||||||
}>) {
|
}>) {
|
||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<body className={` ${GeistSans.className} ${instrumentSerif.className}`}>
|
<body className={`${GeistSans.variable} ${instrumentSerif.variable} font-sans antialiased`}>
|
||||||
|
<NuqsAdapter>
|
||||||
<Providers>
|
<Providers>
|
||||||
<Toaster position="top-center" richColors />
|
<Toaster position="top-center" richColors />
|
||||||
{children}
|
{children}
|
||||||
</Providers>
|
</Providers>
|
||||||
|
</NuqsAdapter>
|
||||||
<Analytics />
|
<Analytics />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
230
app/page.tsx
230
app/page.tsx
@ -2,137 +2,133 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import 'katex/dist/katex.min.css';
|
import 'katex/dist/katex.min.css';
|
||||||
|
|
||||||
import
|
import { BorderTrail } from '@/components/core/border-trail';
|
||||||
React,
|
import { TextShimmer } from '@/components/core/text-shimmer';
|
||||||
{
|
import { FlightTracker } from '@/components/flight-tracker';
|
||||||
useRef,
|
import { InstallPrompt } from '@/components/InstallPrompt';
|
||||||
useCallback,
|
import InteractiveChart from '@/components/interactive-charts';
|
||||||
useState,
|
import { MapComponent, MapContainer } from '@/components/map-components';
|
||||||
useEffect,
|
import TMDBResult from '@/components/movie-info';
|
||||||
useMemo,
|
import MultiSearch from '@/components/multi-search';
|
||||||
Suspense
|
import NearbySearchMapView from '@/components/nearby-search-map-view';
|
||||||
} from 'react';
|
import TrendingResults from '@/components/trending-tv-movies-results';
|
||||||
import ReactMarkdown from 'react-markdown';
|
|
||||||
import { useTheme } from 'next-themes';
|
|
||||||
import Marked, { ReactRenderer } from 'marked-react';
|
|
||||||
import Latex from 'react-latex-next';
|
|
||||||
import { useSearchParams } from 'next/navigation';
|
|
||||||
import { useChat } from 'ai/react';
|
|
||||||
import { ToolInvocation } from 'ai';
|
|
||||||
import { toast } from 'sonner';
|
|
||||||
import { motion, AnimatePresence } from 'framer-motion';
|
|
||||||
import Image from 'next/image';
|
|
||||||
import {
|
|
||||||
fetchMetadata,
|
|
||||||
generateSpeech,
|
|
||||||
suggestQuestions
|
|
||||||
} from './actions';
|
|
||||||
import { Wave } from "@foobar404/wave";
|
|
||||||
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
|
||||||
import { oneLight, oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism';
|
|
||||||
import {
|
|
||||||
Sparkles,
|
|
||||||
ArrowRight,
|
|
||||||
Globe,
|
|
||||||
AlignLeft,
|
|
||||||
Copy,
|
|
||||||
Cloud,
|
|
||||||
Code,
|
|
||||||
Check,
|
|
||||||
Loader2,
|
|
||||||
User2,
|
|
||||||
Heart,
|
|
||||||
X,
|
|
||||||
MapPin,
|
|
||||||
Plus,
|
|
||||||
Download,
|
|
||||||
Flame,
|
|
||||||
Sun,
|
|
||||||
Pause,
|
|
||||||
Play,
|
|
||||||
TrendingUpIcon,
|
|
||||||
Calendar,
|
|
||||||
Calculator,
|
|
||||||
ChevronDown,
|
|
||||||
Edit2,
|
|
||||||
ChevronUp,
|
|
||||||
Moon,
|
|
||||||
Star,
|
|
||||||
YoutubeIcon,
|
|
||||||
LucideIcon,
|
|
||||||
FileText,
|
|
||||||
Book,
|
|
||||||
ExternalLink,
|
|
||||||
Building,
|
|
||||||
Users,
|
|
||||||
Brain,
|
|
||||||
TrendingUp,
|
|
||||||
Plane,
|
|
||||||
Film,
|
|
||||||
Tv,
|
|
||||||
ListTodo
|
|
||||||
} from 'lucide-react';
|
|
||||||
import {
|
|
||||||
HoverCard,
|
|
||||||
HoverCardContent,
|
|
||||||
HoverCardTrigger,
|
|
||||||
} from "@/components/ui/hover-card";
|
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
|
||||||
import {
|
import {
|
||||||
Accordion,
|
Accordion,
|
||||||
AccordionContent,
|
AccordionContent,
|
||||||
AccordionItem,
|
AccordionItem,
|
||||||
AccordionTrigger,
|
AccordionTrigger,
|
||||||
} from "@/components/ui/accordion";
|
} from "@/components/ui/accordion";
|
||||||
import {
|
|
||||||
Tooltip,
|
|
||||||
TooltipContent,
|
|
||||||
TooltipProvider,
|
|
||||||
TooltipTrigger,
|
|
||||||
} from "@/components/ui/tooltip"
|
|
||||||
import { Input } from '@/components/ui/input';
|
|
||||||
import { Button } from '@/components/ui/button';
|
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
CardHeader,
|
CardHeader,
|
||||||
CardTitle,
|
CardTitle,
|
||||||
} from "@/components/ui/card";
|
} from "@/components/ui/card";
|
||||||
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
|
|
||||||
import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerTrigger } from "@/components/ui/drawer";
|
|
||||||
import { GitHubLogoIcon, TextIcon } from '@radix-ui/react-icons';
|
|
||||||
import Link from 'next/link';
|
|
||||||
import { Dialog, DialogContent } from "@/components/ui/dialog";
|
|
||||||
import { Carousel, CarouselContent, CarouselItem } from "@/components/ui/carousel";
|
import { Carousel, CarouselContent, CarouselItem } from "@/components/ui/carousel";
|
||||||
import { cn, SearchGroupId } from '@/lib/utils';
|
import { Dialog, DialogContent } from "@/components/ui/dialog";
|
||||||
|
import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerTrigger } from "@/components/ui/drawer";
|
||||||
|
import FormComponent from '@/components/ui/form-component';
|
||||||
|
import {
|
||||||
|
HoverCard,
|
||||||
|
HoverCardContent,
|
||||||
|
HoverCardTrigger,
|
||||||
|
} from "@/components/ui/hover-card";
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
|
import { Separator } from '@/components/ui/separator';
|
||||||
|
import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
TableCell,
|
TableCell,
|
||||||
TableRow,
|
TableRow,
|
||||||
} from "@/components/ui/table";
|
} from "@/components/ui/table";
|
||||||
import Autoplay from 'embla-carousel-autoplay';
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
import FormComponent from '@/components/ui/form-component';
|
import {
|
||||||
|
Tooltip,
|
||||||
|
TooltipContent,
|
||||||
|
TooltipProvider,
|
||||||
|
TooltipTrigger,
|
||||||
|
} from "@/components/ui/tooltip";
|
||||||
import WeatherChart from '@/components/weather-chart';
|
import WeatherChart from '@/components/weather-chart';
|
||||||
import InteractiveChart from '@/components/interactive-charts';
|
|
||||||
import { MapComponent, MapContainer } from '@/components/map-components';
|
|
||||||
import MultiSearch from '@/components/multi-search';
|
|
||||||
import { CurrencyDollar, Flag, RoadHorizon, SoccerBall, TennisBall, XLogo } from '@phosphor-icons/react';
|
|
||||||
import { BorderTrail } from '@/components/core/border-trail';
|
|
||||||
import { TextShimmer } from '@/components/core/text-shimmer';
|
|
||||||
import { Tweet } from 'react-tweet';
|
|
||||||
import NearbySearchMapView from '@/components/nearby-search-map-view';
|
|
||||||
import { Separator } from '@/components/ui/separator';
|
|
||||||
import { TrendingQuery } from './api/trending/route';
|
|
||||||
import { FlightTracker } from '@/components/flight-tracker';
|
|
||||||
import { InstallPrompt } from '@/components/InstallPrompt';
|
|
||||||
import { atomDark } from 'react-syntax-highlighter/dist/cjs/styles/prism';
|
|
||||||
import { vs } from 'react-syntax-highlighter/dist/cjs/styles/prism';
|
|
||||||
import { useMediaQuery } from '@/hooks/use-media-query';
|
import { useMediaQuery } from '@/hooks/use-media-query';
|
||||||
import TMDBResult from '@/components/movie-info';
|
import { cn, SearchGroupId } from '@/lib/utils';
|
||||||
import TrendingResults from '@/components/trending-tv-movies-results';
|
import { Wave } from "@foobar404/wave";
|
||||||
|
import { CurrencyDollar, Flag, RoadHorizon, SoccerBall, TennisBall, XLogo } from '@phosphor-icons/react';
|
||||||
|
import { GitHubLogoIcon, TextIcon } from '@radix-ui/react-icons';
|
||||||
|
import { ToolInvocation } from 'ai';
|
||||||
|
import { useChat } from 'ai/react';
|
||||||
|
import Autoplay from 'embla-carousel-autoplay';
|
||||||
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
import { GeistMono } from 'geist/font/mono';
|
import { GeistMono } from 'geist/font/mono';
|
||||||
|
import {
|
||||||
|
AlignLeft,
|
||||||
|
ArrowRight,
|
||||||
|
Book,
|
||||||
|
Brain,
|
||||||
|
Building,
|
||||||
|
Calculator,
|
||||||
|
Calendar,
|
||||||
|
Check,
|
||||||
|
ChevronDown,
|
||||||
|
ChevronUp,
|
||||||
|
Cloud,
|
||||||
|
Code,
|
||||||
|
Copy,
|
||||||
|
Download,
|
||||||
|
Edit2,
|
||||||
|
ExternalLink,
|
||||||
|
FileText,
|
||||||
|
Film,
|
||||||
|
Flame,
|
||||||
|
Globe,
|
||||||
|
Heart,
|
||||||
|
ListTodo,
|
||||||
|
Loader2,
|
||||||
|
LucideIcon,
|
||||||
|
MapPin,
|
||||||
|
Moon,
|
||||||
|
Pause,
|
||||||
|
Plane,
|
||||||
|
Play,
|
||||||
|
Plus,
|
||||||
|
Sparkles,
|
||||||
|
Sun,
|
||||||
|
TrendingUp,
|
||||||
|
TrendingUpIcon,
|
||||||
|
Tv,
|
||||||
|
User2,
|
||||||
|
Users,
|
||||||
|
X,
|
||||||
|
YoutubeIcon
|
||||||
|
} from 'lucide-react';
|
||||||
|
import Marked, { ReactRenderer } from 'marked-react';
|
||||||
|
import { useTheme } from 'next-themes';
|
||||||
|
import Image from 'next/image';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import { parseAsString, useQueryState } from 'nuqs';
|
||||||
|
import React, {
|
||||||
|
Suspense,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState
|
||||||
|
} from 'react';
|
||||||
|
import Latex from 'react-latex-next';
|
||||||
|
import ReactMarkdown from 'react-markdown';
|
||||||
|
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
||||||
|
import { atomDark, vs } from 'react-syntax-highlighter/dist/cjs/styles/prism';
|
||||||
|
import { oneDark, oneLight } from 'react-syntax-highlighter/dist/esm/styles/prism';
|
||||||
|
import { Tweet } from 'react-tweet';
|
||||||
|
import { toast } from 'sonner';
|
||||||
|
import {
|
||||||
|
fetchMetadata,
|
||||||
|
generateSpeech,
|
||||||
|
suggestQuestions
|
||||||
|
} from './actions';
|
||||||
|
import { TrendingQuery } from './api/trending/route';
|
||||||
|
|
||||||
export const maxDuration = 60;
|
export const maxDuration = 60;
|
||||||
|
|
||||||
@ -563,12 +559,15 @@ const SponsorDialog = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const HomeContent = () => {
|
const HomeContent = () => {
|
||||||
const searchParams = useSearchParams();
|
const [query] = useQueryState('query', parseAsString.withDefault(''))
|
||||||
|
const [q] = useQueryState('q', parseAsString.withDefault(''))
|
||||||
|
const [model] = useQueryState('model', parseAsString.withDefault('grok-2-1212'))
|
||||||
|
|
||||||
// Memoize initial values to prevent re-calculation
|
// Memoize initial values to prevent re-calculation
|
||||||
const initialState = useMemo(() => ({
|
const initialState = useMemo(() => ({
|
||||||
query: searchParams.get('query') || searchParams.get('q') || '',
|
query: query || q,
|
||||||
model: searchParams.get('model') || 'grok-2-1212'
|
model: model
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}), []); // Empty dependency array as we only want this on mount
|
}), []); // Empty dependency array as we only want this on mount
|
||||||
|
|
||||||
const lastSubmittedQueryRef = useRef(initialState.query);
|
const lastSubmittedQueryRef = useRef(initialState.query);
|
||||||
@ -699,6 +698,7 @@ const HomeContent = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fetchTrending();
|
fetchTrending();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const ThemeToggle: React.FC = () => {
|
const ThemeToggle: React.FC = () => {
|
||||||
@ -892,10 +892,11 @@ Grok 2 models are now available for you to try out.
|
|||||||
const waveRef = useRef<Wave | null>(null);
|
const waveRef = useRef<Wave | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const _audioRef = audioRef.current
|
||||||
return () => {
|
return () => {
|
||||||
if (audioRef.current) {
|
if (_audioRef) {
|
||||||
audioRef.current.pause();
|
_audioRef.pause();
|
||||||
audioRef.current.src = '';
|
_audioRef.src = '';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
@ -2588,6 +2589,7 @@ Grok 2 models are now available for you to try out.
|
|||||||
<SuggestionCards
|
<SuggestionCards
|
||||||
trendingQueries={trendingQueries}
|
trendingQueries={trendingQueries}
|
||||||
/>
|
/>
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
), [trendingQueries]);
|
), [trendingQueries]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
60
docker-compose.yaml
Normal file
60
docker-compose.yaml
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
web:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- XAI_API_KEY=${XAI_API_KEY}
|
||||||
|
- UPSTASH_REDIS_REST_URL=${UPSTASH_REDIS_REST_URL}
|
||||||
|
- UPSTASH_REDIS_REST_TOKEN=${UPSTASH_REDIS_REST_TOKEN}
|
||||||
|
- ELEVENLABS_API_KEY=${ELEVENLABS_API_KEY}
|
||||||
|
- TAVILY_API_KEY=${TAVILY_API_KEY}
|
||||||
|
- EXA_API_KEY=${EXA_API_KEY}
|
||||||
|
- TMDB_API_KEY=${TMDB_API_KEY}
|
||||||
|
- YT_ENDPOINT=${YT_ENDPOINT}
|
||||||
|
- FIRECRAWL_API_KEY=${FIRECRAWL_API_KEY}
|
||||||
|
- OPENWEATHER_API_KEY=${OPENWEATHER_API_KEY}
|
||||||
|
- SANDBOX_TEMPLATE_ID=${SANDBOX_TEMPLATE_ID}
|
||||||
|
- GOOGLE_MAPS_API_KEY=${GOOGLE_MAPS_API_KEY}
|
||||||
|
- MAPBOX_ACCESS_TOKEN=${MAPBOX_ACCESS_TOKEN}
|
||||||
|
- AZURE_TRANSLATOR_KEY=${AZURE_TRANSLATOR_KEY}
|
||||||
|
- AZURE_TRANSLATOR_LOCATION=${AZURE_TRANSLATOR_LOCATION}
|
||||||
|
- AZURE_RESOURCE_NAME=${AZURE_RESOURCE_NAME}
|
||||||
|
- AZURE_API_KEY=${AZURE_API_KEY}
|
||||||
|
- TRIPADVISOR_API_KEY=${TRIPADVISOR_API_KEY}
|
||||||
|
- AVIATION_STACK_API_KEY=${AVIATION_STACK_API_KEY}
|
||||||
|
- CRON_SECRET=${CRON_SECRET}
|
||||||
|
- BLOB_READ_WRITE_TOKEN=${BLOB_READ_WRITE_TOKEN}
|
||||||
|
- NEXT_PUBLIC_MAPBOX_TOKEN=${NEXT_PUBLIC_MAPBOX_TOKEN}
|
||||||
|
- NEXT_PUBLIC_POSTHOG_KEY=${NEXT_PUBLIC_POSTHOG_KEY}
|
||||||
|
- NEXT_PUBLIC_POSTHOG_HOST=${NEXT_PUBLIC_POSTHOG_HOST}
|
||||||
|
- NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=${NEXT_PUBLIC_GOOGLE_MAPS_API_KEY}
|
||||||
|
volumes:
|
||||||
|
- .:/app
|
||||||
|
- /app/node_modules
|
||||||
|
depends_on:
|
||||||
|
- code-interpreter
|
||||||
|
|
||||||
|
code-interpreter:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: e2b.Dockerfile
|
||||||
|
environment:
|
||||||
|
- E2B_API_KEY=${E2B_API_KEY}
|
||||||
|
volumes:
|
||||||
|
- ./certificates:/app/certificates
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:alpine
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
volumes:
|
||||||
|
- redis_data:/data
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
redis_data:
|
||||||
3
env/client.ts
vendored
3
env/client.ts
vendored
@ -7,10 +7,13 @@ export const clientEnv = createEnv({
|
|||||||
NEXT_PUBLIC_MAPBOX_TOKEN: z.string().min(1),
|
NEXT_PUBLIC_MAPBOX_TOKEN: z.string().min(1),
|
||||||
NEXT_PUBLIC_POSTHOG_KEY: z.string().min(1),
|
NEXT_PUBLIC_POSTHOG_KEY: z.string().min(1),
|
||||||
NEXT_PUBLIC_POSTHOG_HOST: z.string().min(1).url(),
|
NEXT_PUBLIC_POSTHOG_HOST: z.string().min(1).url(),
|
||||||
|
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY: z.string().min(1),
|
||||||
},
|
},
|
||||||
runtimeEnv: {
|
runtimeEnv: {
|
||||||
NEXT_PUBLIC_MAPBOX_TOKEN: process.env.NEXT_PUBLIC_MAPBOX_TOKEN,
|
NEXT_PUBLIC_MAPBOX_TOKEN: process.env.NEXT_PUBLIC_MAPBOX_TOKEN,
|
||||||
NEXT_PUBLIC_POSTHOG_KEY: process.env.NEXT_PUBLIC_POSTHOG_KEY,
|
NEXT_PUBLIC_POSTHOG_KEY: process.env.NEXT_PUBLIC_POSTHOG_KEY,
|
||||||
NEXT_PUBLIC_POSTHOG_HOST: process.env.NEXT_PUBLIC_POSTHOG_HOST,
|
NEXT_PUBLIC_POSTHOG_HOST: process.env.NEXT_PUBLIC_POSTHOG_HOST,
|
||||||
|
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY: process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
6
env/server.ts
vendored
6
env/server.ts
vendored
@ -4,6 +4,9 @@ import { z } from 'zod'
|
|||||||
|
|
||||||
export const serverEnv = createEnv({
|
export const serverEnv = createEnv({
|
||||||
server: {
|
server: {
|
||||||
|
XAI_API_KEY: z.string().min(1),
|
||||||
|
UPSTASH_REDIS_REST_URL: z.string().min(1).url(),
|
||||||
|
UPSTASH_REDIS_REST_TOKEN: z.string().min(1),
|
||||||
ELEVENLABS_API_KEY: z.string().min(1),
|
ELEVENLABS_API_KEY: z.string().min(1),
|
||||||
TAVILY_API_KEY: z.string().min(1),
|
TAVILY_API_KEY: z.string().min(1),
|
||||||
EXA_API_KEY: z.string().min(1),
|
EXA_API_KEY: z.string().min(1),
|
||||||
@ -16,9 +19,12 @@ export const serverEnv = createEnv({
|
|||||||
MAPBOX_ACCESS_TOKEN: z.string().min(1),
|
MAPBOX_ACCESS_TOKEN: z.string().min(1),
|
||||||
AZURE_TRANSLATOR_KEY: z.string().min(1),
|
AZURE_TRANSLATOR_KEY: z.string().min(1),
|
||||||
AZURE_TRANSLATOR_LOCATION: z.string().min(1),
|
AZURE_TRANSLATOR_LOCATION: z.string().min(1),
|
||||||
|
AZURE_RESOURCE_NAME: z.string().min(1),
|
||||||
|
AZURE_API_KEY: z.string().min(1),
|
||||||
TRIPADVISOR_API_KEY: z.string().min(1),
|
TRIPADVISOR_API_KEY: z.string().min(1),
|
||||||
AVIATION_STACK_API_KEY: z.string().min(1),
|
AVIATION_STACK_API_KEY: z.string().min(1),
|
||||||
CRON_SECRET: z.string().min(1),
|
CRON_SECRET: z.string().min(1),
|
||||||
|
BLOB_READ_WRITE_TOKEN: z.string().min(1),
|
||||||
},
|
},
|
||||||
experimental__runtimeEnv: process.env,
|
experimental__runtimeEnv: process.env,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -9,7 +9,7 @@ jiti.import('./env/client')
|
|||||||
|
|
||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
transpilePackages: ['geist'],
|
transpilePackages: ["geist"],
|
||||||
async headers() {
|
async headers() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@ -50,45 +50,45 @@ const nextConfig = {
|
|||||||
protocol: 'https',
|
protocol: 'https',
|
||||||
hostname: 'metwm7frkvew6tn1.public.blob.vercel-storage.com',
|
hostname: 'metwm7frkvew6tn1.public.blob.vercel-storage.com',
|
||||||
port: '',
|
port: '',
|
||||||
pathname: '**',
|
pathname: "**"
|
||||||
},
|
},
|
||||||
// upload.wikimedia.org
|
// upload.wikimedia.org
|
||||||
{
|
{
|
||||||
protocol: 'https',
|
protocol: 'https',
|
||||||
hostname: 'upload.wikimedia.org',
|
hostname: 'upload.wikimedia.org',
|
||||||
port: '',
|
port: '',
|
||||||
pathname: '**',
|
pathname: '**'
|
||||||
},
|
},
|
||||||
// media.theresanaiforthat.com
|
// media.theresanaiforthat.com
|
||||||
{
|
{
|
||||||
protocol: 'https',
|
protocol: 'https',
|
||||||
hostname: 'media.theresanaiforthat.com',
|
hostname: 'media.theresanaiforthat.com',
|
||||||
port: '',
|
port: '',
|
||||||
pathname: '**',
|
pathname: '**'
|
||||||
},
|
},
|
||||||
// www.uneed.best
|
// www.uneed.best
|
||||||
{
|
{
|
||||||
protocol: 'https',
|
protocol: 'https',
|
||||||
hostname: 'www.uneed.best',
|
hostname: 'www.uneed.best',
|
||||||
port: '',
|
port: '',
|
||||||
pathname: '**',
|
pathname: '**'
|
||||||
},
|
},
|
||||||
// image.tmdb.org
|
// image.tmdb.org
|
||||||
{
|
{
|
||||||
protocol: 'https',
|
protocol: 'https',
|
||||||
hostname: 'image.tmdb.org',
|
hostname: 'image.tmdb.org',
|
||||||
port: '',
|
port: '',
|
||||||
pathname: '/t/p/original/**',
|
pathname: '/t/p/original/**'
|
||||||
},
|
},
|
||||||
// image.tmdb.org
|
// image.tmdb.org
|
||||||
{
|
{
|
||||||
protocol: 'https',
|
protocol: 'https',
|
||||||
hostname: 'image.tmdb.org',
|
hostname: 'image.tmdb.org',
|
||||||
port: '',
|
port: '',
|
||||||
pathname: '/**',
|
pathname: '/**'
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
export default nextConfig
|
export default nextConfig;
|
||||||
|
|||||||
@ -64,6 +64,7 @@
|
|||||||
"motion": "^11.13.5",
|
"motion": "^11.13.5",
|
||||||
"next": "^14.2.21",
|
"next": "^14.2.21",
|
||||||
"next-themes": "^0.3.0",
|
"next-themes": "^0.3.0",
|
||||||
|
"nuqs": "^2.3.0",
|
||||||
"openai": "^4.56.0",
|
"openai": "^4.56.0",
|
||||||
"posthog-js": "^1.202.2",
|
"posthog-js": "^1.202.2",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
|
|||||||
@ -173,6 +173,9 @@ importers:
|
|||||||
next-themes:
|
next-themes:
|
||||||
specifier: ^0.3.0
|
specifier: ^0.3.0
|
||||||
version: 0.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
version: 0.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
nuqs:
|
||||||
|
specifier: ^2.3.0
|
||||||
|
version: 2.3.0(next@14.2.21(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
|
||||||
openai:
|
openai:
|
||||||
specifier: ^4.56.0
|
specifier: ^4.56.0
|
||||||
version: 4.67.2(zod@3.24.1)
|
version: 4.67.2(zod@3.24.1)
|
||||||
@ -2786,6 +2789,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
|
resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==}
|
||||||
engines: {node: '>=16 || 14 >=14.17'}
|
engines: {node: '>=16 || 14 >=14.17'}
|
||||||
|
|
||||||
|
mitt@3.0.1:
|
||||||
|
resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
|
||||||
|
|
||||||
motion-dom@11.13.0:
|
motion-dom@11.13.0:
|
||||||
resolution: {integrity: sha512-Oc1MLGJQ6nrvXccXA89lXtOqFyBmvHtaDcTRGT66o8Czl7nuA8BeHAd9MQV1pQKX0d2RHFBFaw5g3k23hQJt0w==}
|
resolution: {integrity: sha512-Oc1MLGJQ6nrvXccXA89lXtOqFyBmvHtaDcTRGT66o8Czl7nuA8BeHAd9MQV1pQKX0d2RHFBFaw5g3k23hQJt0w==}
|
||||||
|
|
||||||
@ -2877,6 +2883,24 @@ packages:
|
|||||||
nth-check@2.1.1:
|
nth-check@2.1.1:
|
||||||
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
|
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
|
||||||
|
|
||||||
|
nuqs@2.3.0:
|
||||||
|
resolution: {integrity: sha512-ChS56bJZdaTQzCJb6jPel6cIHYh8/V/GSIjZoIe5yAssGdcrVaBFBgzHfJW6IewbR6yc1Zch2CmGsdgztR+xmA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@remix-run/react': '>=2'
|
||||||
|
next: '>=14.2.0'
|
||||||
|
react: '>=18.2.0 || ^19.0.0-0'
|
||||||
|
react-router: ^7
|
||||||
|
react-router-dom: ^6 || ^7
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@remix-run/react':
|
||||||
|
optional: true
|
||||||
|
next:
|
||||||
|
optional: true
|
||||||
|
react-router:
|
||||||
|
optional: true
|
||||||
|
react-router-dom:
|
||||||
|
optional: true
|
||||||
|
|
||||||
object-assign@4.1.1:
|
object-assign@4.1.1:
|
||||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@ -6735,6 +6759,8 @@ snapshots:
|
|||||||
|
|
||||||
minipass@7.1.2: {}
|
minipass@7.1.2: {}
|
||||||
|
|
||||||
|
mitt@3.0.1: {}
|
||||||
|
|
||||||
motion-dom@11.13.0: {}
|
motion-dom@11.13.0: {}
|
||||||
|
|
||||||
motion-utils@11.13.0: {}
|
motion-utils@11.13.0: {}
|
||||||
@ -6808,6 +6834,13 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
boolbase: 1.0.0
|
boolbase: 1.0.0
|
||||||
|
|
||||||
|
nuqs@2.3.0(next@14.2.21(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1):
|
||||||
|
dependencies:
|
||||||
|
mitt: 3.0.1
|
||||||
|
react: 18.3.1
|
||||||
|
optionalDependencies:
|
||||||
|
next: 14.2.21(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||||
|
|
||||||
object-assign@4.1.1: {}
|
object-assign@4.1.1: {}
|
||||||
|
|
||||||
object-hash@3.0.0: {}
|
object-hash@3.0.0: {}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import type { Config } from "tailwindcss";
|
import type { Config } from "tailwindcss";
|
||||||
|
import { fontFamily } from 'tailwindcss/defaultTheme';
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
darkMode: ["class"],
|
darkMode: ["class"],
|
||||||
@ -23,9 +24,9 @@ const config = {
|
|||||||
'screen-small': '100svh',
|
'screen-small': '100svh',
|
||||||
},
|
},
|
||||||
fontFamily: {
|
fontFamily: {
|
||||||
sans: ['var(--font-geist-sans)'],
|
sans: ['var(--font-geist-sans)', ...fontFamily.sans],
|
||||||
serif: ['var(--font-serif)'],
|
serif: ['var(--font-serif)', ...fontFamily.serif],
|
||||||
mono: ['var(--font-geist-mono)'],
|
mono: ['var(--font-geist-mono)', ...fontFamily.mono],
|
||||||
},
|
},
|
||||||
colors: {
|
colors: {
|
||||||
border: "hsl(var(--border))",
|
border: "hsl(var(--border))",
|
||||||
@ -87,7 +88,11 @@ const config = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [require("tailwindcss-animate"), require("@tailwindcss/typography"),require("tailwind-scrollbar")],
|
plugins: [
|
||||||
|
require("tailwindcss-animate"),
|
||||||
|
require("@tailwindcss/typography"),
|
||||||
|
require("tailwind-scrollbar")
|
||||||
|
],
|
||||||
} satisfies Config
|
} satisfies Config
|
||||||
|
|
||||||
export default config
|
export default config
|
||||||
Loading…
Reference in New Issue
Block a user