WIP: Interactive charts and MapBox integration

This commit is contained in:
zaidmukaddam 2024-11-05 13:12:18 +05:30
parent a3415adee1
commit 065bbe7887
10 changed files with 965 additions and 450 deletions

View File

@ -1,6 +1,5 @@
'use server';
import { OpenAI } from 'openai';
import { generateObject } from 'ai';
import { createOpenAI as createGroq } from '@ai-sdk/openai';
import { z } from 'zod';
@ -15,7 +14,7 @@ export async function suggestQuestions(history: any[]) {
'use server';
const { object } = await generateObject({
model: groq('llama-3.2-90b-text-preview'),
model: groq('llama-3.2-11b-text-preview'),
temperature: 0,
system:
`You are a search engine query generator. You 'have' to create only '3' questions for the search engine based on the message history which has been provided to you.

View File

@ -5,10 +5,10 @@ import {
convertToCoreMessages,
streamText,
tool,
experimental_createProviderRegistry
experimental_createProviderRegistry,
} from "ai";
import { BlobRequestAbortedError, put } from '@vercel/blob';
import { CodeInterpreter } from "@e2b/code-interpreter";
import CodeInterpreter from "@e2b/code-interpreter";
import FirecrawlApp from '@mendable/firecrawl-js';
// Allow streaming responses up to 60 seconds
@ -38,12 +38,23 @@ type SearchResultImage =
number_of_results?: number
}
// Helper function to geocode an address
const geocodeAddress = async (address: string) => {
const mapboxToken = process.env.MAPBOX_ACCESS_TOKEN;
const response = await fetch(
`https://api.mapbox.com/geocoding/v5/mapbox.places/${encodeURIComponent(address)}.json?access_token=${mapboxToken}`
);
const data = await response.json();
return data.features[0];
};
export async function POST(req: Request) {
const { messages, model } = await req.json();
const provider = model.split(":")[0];
const result = await streamText({
maxSteps: 10,
model: registry.languageModel(model),
messages: convertToCoreMessages(messages),
temperature: provider === "azure" ? 0.72 : 0,
@ -365,7 +376,7 @@ When asked a "What is" question, maintain the same format as the question and an
}),
execute: async ({ code }: { code: string }) => {
const sandbox = await CodeInterpreter.create();
const execution = await sandbox.notebook.execCell(code);
const execution = await sandbox.runCode(code);
let message = "";
let images = [];
@ -424,98 +435,177 @@ When asked a "What is" question, maintain the same format as the question and an
}
}
sandbox.close();
return { message: message.trim(), images };
if (execution.error) {
message += `Error: ${execution.error}\n`;
console.log("Error: ", execution.error);
}
console.log(execution.results[0].chart)
if (execution.results[0].chart) {
execution.results[0].chart.elements.map((element: any) => {
console.log(element.points)
})
}
return { message: message.trim(), images, chart: execution.results[0].chart ?? "" };
},
}),
nearby_search: tool({
description: "Search for nearby places using Google Maps API.",
description: "Search for nearby places using Mapbox API.",
parameters: z.object({
location: z.string().describe("The location to search near (e.g., 'New York City' or '1600 Amphitheatre Parkway, Mountain View, CA')."),
type: z.string().describe("The type of place to search for (e.g., restaurant, cafe, park)."),
keyword: z.string().describe("An optional keyword to refine the search."),
radius: z.number().default(3000).describe("The radius of the search area in meters (max 50000, default 3000)."),
}),
execute: async ({ location, type, keyword, radius }: { location: string; type: string; keyword?: string; radius: number }) => {
const apiKey = process.env.GOOGLE_MAPS_API_KEY;
execute: async ({ location, type, keyword, radius }: {
location: string;
type: string;
keyword?: string;
radius: number;
}) => {
const mapboxToken = process.env.MAPBOX_ACCESS_TOKEN;
// First, use the Geocoding API to get the coordinates
const geocodeUrl = `https://maps.googleapis.com/maps/api/geocode/json?address=${encodeURIComponent(location)}&key=${apiKey}`;
const geocodeResponse = await fetch(geocodeUrl);
const geocodeData = await geocodeResponse.json();
if (geocodeData.status !== "OK" || !geocodeData.results[0]) {
throw new Error("Failed to geocode the location");
}
const { lat, lng } = geocodeData.results[0].geometry.location;
// perform the nearby search
let searchUrl = `https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=${lat},${lng}&radius=${radius}&type=${type}&key=${apiKey}`;
// First geocode the location
const locationData = await geocodeAddress(location);
const [lng, lat] = locationData.center;
// Construct search query
let searchQuery = type;
if (keyword) {
searchUrl += `&keyword=${encodeURIComponent(keyword)}`;
searchQuery = `${keyword} ${type}`;
}
const searchResponse = await fetch(searchUrl);
const searchData = await searchResponse.json();
// Search for places using Mapbox Geocoding API
const response = await fetch(
`https://api.mapbox.com/geocoding/v5/mapbox.places/${encodeURIComponent(searchQuery)}.json?proximity=${lng},${lat}&limit=10&types=poi&access_token=${mapboxToken}`
);
const data = await response.json();
// Filter results by distance
const radiusInDegrees = radius / 111320; // Approximate conversion from meters to degrees
const results = data.features
.filter((feature: any) => {
const [placeLng, placeLat] = feature.center;
const distance = Math.sqrt(
Math.pow(placeLng - lng, 2) + Math.pow(placeLat - lat, 2)
);
return distance <= radiusInDegrees;
})
.map((feature: any) => ({
name: feature.text,
vicinity: feature.place_name,
place_id: feature.id,
location: {
lat: feature.center[1],
lng: feature.center[0]
},
// Note: Mapbox doesn't provide ratings, so we'll exclude those
}));
return {
results: searchData.results.slice(0, 5).map((place: any) => ({
name: place.name,
vicinity: place.vicinity,
rating: place.rating,
user_ratings_total: place.user_ratings_total,
place_id: place.place_id,
location: place.geometry.location,
})),
results: results.slice(0, 5),
center: { lat, lng },
formatted_address: geocodeData.results[0].formatted_address,
formatted_address: locationData.place_name,
};
},
}),
find_place: tool({
description: "Find a specific place using Google Maps API.",
description: "Find a specific place using Mapbox API.",
parameters: z.object({
input: z.string().describe("The place to search for (e.g., 'Museum of Contemporary Art Australia')."),
inputtype: z.enum(["textquery", "phonenumber"]).describe("The type of input (textquery or phonenumber)."),
}),
execute: async ({ input, inputtype }: { input: string; inputtype: "textquery" | "phonenumber" }) => {
console.log("input", input);
const apiKey = process.env.GOOGLE_MAPS_API_KEY;
const url = `https://maps.googleapis.com/maps/api/place/findplacefromtext/json?fields=formatted_address,name,rating,opening_hours,geometry&input=${encodeURIComponent(input)}&inputtype=${inputtype}&key=${apiKey}`;
execute: async ({ input, inputtype }: {
input: string;
inputtype: "textquery" | "phonenumber";
}) => {
const mapboxToken = process.env.MAPBOX_ACCESS_TOKEN;
const response = await fetch(url);
let searchEndpoint = `https://api.mapbox.com/geocoding/v5/mapbox.places/${encodeURIComponent(input)}.json`;
if (inputtype === "phonenumber") {
// Note: Mapbox doesn't support phone number search directly
// We'll just search the number as text
searchEndpoint = `https://api.mapbox.com/geocoding/v5/mapbox.places/${encodeURIComponent(input)}.json`;
}
const response = await fetch(`${searchEndpoint}?types=poi&access_token=${mapboxToken}`);
const data = await response.json();
return data;
if (!data.features || data.features.length === 0) {
return { candidates: [] };
}
const place = data.features[0];
return {
candidates: [{
name: place.text,
formatted_address: place.place_name,
geometry: {
location: {
lat: place.center[1],
lng: place.center[0]
}
},
// Note: Mapbox doesn't provide these fields
rating: null,
opening_hours: null
}]
};
},
}),
text_search: tool({
description: "Perform a text-based search for places using Google Maps API.",
description: "Perform a text-based search for places using Mapbox API.",
parameters: z.object({
query: z.string().describe("The search query (e.g., '123 main street')."),
location: z.string().describe("The location to center the search (e.g., '42.3675294,-71.186966')."),
radius: z.number().describe("The radius of the search area in meters (max 50000)."),
}),
execute: async ({ query, location, radius }: { query: string; location?: string; radius?: number }) => {
const apiKey = process.env.GOOGLE_MAPS_API_KEY;
console.log("query", query);
console.log("location", location);
console.log("radius", radius);
let url = `https://maps.googleapis.com/maps/api/place/textsearch/json?query=${encodeURIComponent(query)}&key=${apiKey}`;
execute: async ({ query, location, radius }: {
query: string;
location?: string;
radius?: number;
}) => {
const mapboxToken = process.env.MAPBOX_ACCESS_TOKEN;
let proximity = '';
if (location) {
url += `&location=${encodeURIComponent(location)}`;
}
if (radius) {
url += `&radius=${radius}`;
const [lng, lat] = location.split(',').map(Number);
proximity = `&proximity=${lng},${lat}`;
}
const response = await fetch(url);
const response = await fetch(
`https://api.mapbox.com/geocoding/v5/mapbox.places/${encodeURIComponent(query)}.json?types=poi${proximity}&access_token=${mapboxToken}`
);
const data = await response.json();
return data;
// If location and radius provided, filter results by distance
let results = data.features;
if (location && radius) {
const [centerLng, centerLat] = location.split(',').map(Number);
const radiusInDegrees = radius / 111320;
results = results.filter((feature: any) => {
const [placeLng, placeLat] = feature.center;
const distance = Math.sqrt(
Math.pow(placeLng - centerLng, 2) + Math.pow(placeLat - centerLat, 2)
);
return distance <= radiusInDegrees;
});
}
return {
results: results.map((feature: any) => ({
name: feature.text,
formatted_address: feature.place_name,
geometry: {
location: {
lat: feature.center[1],
lng: feature.center[0]
}
}
}))
};
},
}),
text_translate: tool({

View File

@ -1,6 +1,6 @@
import { cohere } from '@ai-sdk/cohere'
import { convertToCoreMessages, streamText, tool } from "ai";
import { CodeInterpreter } from "@e2b/code-interpreter";
import CodeInterpreter from "@e2b/code-interpreter";
import { z } from "zod";
import { geolocation } from "@vercel/functions";
@ -272,7 +272,7 @@ Remember to always run the appropriate tool(s) first and compose your response b
}),
execute: async ({ code }: { code: string }) => {
const sandbox = await CodeInterpreter.create();
const execution = await sandbox.notebook.execCell(code);
const execution = await sandbox.runCode(code);
let message = "";
let images = [];
@ -307,7 +307,6 @@ Remember to always run the appropriate tool(s) first and compose your response b
}
}
sandbox.close();
return { message: message.trim(), images };
},
}),

View File

@ -1,5 +1,6 @@
import "./globals.css";
import 'katex/dist/katex.min.css';
import 'mapbox-gl/dist/mapbox-gl.css';
import { Metadata, Viewport } from "next";
import { Toaster } from "sonner";
import { Inter, Instrument_Serif, IBM_Plex_Mono } from 'next/font/google';

View File

@ -19,7 +19,7 @@ import Marked, { ReactRenderer } from 'marked-react';
import { track } from '@vercel/analytics';
import { useSearchParams } from 'next/navigation';
import { useChat } from 'ai/react';
import { ChatRequestOptions, CreateMessage, Message, ToolInvocation } from 'ai';
import { ToolInvocation } from 'ai';
import { toast } from 'sonner';
import { motion, AnimatePresence } from 'framer-motion';
import Image from 'next/image';
@ -88,32 +88,17 @@ import {
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Line, LineChart, CartesianGrid, XAxis, YAxis, ResponsiveContainer } from "recharts";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import {
ChartConfig,
ChartContainer,
ChartTooltip,
ChartTooltipContent,
} from "@/components/ui/chart";
import { GitHubLogoIcon, PlusCircledIcon } from '@radix-ui/react-icons';
import { Skeleton } from '@/components/ui/skeleton';
import Link from 'next/link';
import { Dialog, DialogContent } from "@/components/ui/dialog";
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from "@/components/ui/carousel";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { cn } from '@/lib/utils';
import {
Table,
@ -124,6 +109,8 @@ import {
import Autoplay from 'embla-carousel-autoplay';
import FormComponent from '@/components/ui/form-component';
import WeatherChart from '@/components/weather-chart';
import { MapContainer } from '@/components/map-components';
import InteractiveChart from '@/components/interactive-charts';
export const maxDuration = 60;
@ -884,7 +871,7 @@ GPT-4o has been re-enabled! You can use it by selecting the model from the dropd
<MapPin className="h-5 w-5 text-neutral-700 dark:text-neutral-300 animate-pulse" />
<span className="text-neutral-700 dark:text-neutral-300 text-lg">Searching nearby places...</span>
</div>
<div className="flex space-x-1">
<motion.div className="flex space-x-1">
{[0, 1, 2].map((index) => (
<motion.div
key={index}
@ -899,49 +886,18 @@ GPT-4o has been re-enabled! You can use it by selecting the model from the dropd
}}
/>
))}
</div>
</motion.div>
</div>
);
}
if (isLoading) {
return (
<Card className="w-full my-4 overflow-hidden bg-white dark:bg-neutral-800 border-neutral-200 dark:border-neutral-700">
<CardHeader>
<Skeleton className="h-6 w-3/4 bg-neutral-200 dark:bg-neutral-700" />
</CardHeader>
<CardContent className="p-0 rounded-t-none rounded-b-xl">
<MapSkeleton />
</CardContent>
</Card>
);
}
return (
<Card className="w-full my-4 overflow-hidden bg-white dark:bg-neutral-800 border-neutral-200 dark:border-neutral-700">
<CardHeader>
<CardTitle className="flex items-center gap-2 text-neutral-800 dark:text-neutral-100">
<MapPin className="h-5 w-5 text-primary" />
<span>Nearby {args.type ? args.type.charAt(0).toUpperCase() + args.type.slice(1) + 's' : 'Places'}</span>
{args.keyword && <Badge variant="secondary" className="bg-neutral-200 dark:bg-neutral-700 text-neutral-800 dark:text-neutral-200">{args.keyword}</Badge>}
</CardTitle>
</CardHeader>
<CardContent className="p-0">
<MapComponent center={result.center} places={result.results} />
<Accordion type="single" collapsible className="w-full">
<AccordionItem value="place-details">
<AccordionTrigger className="px-4 text-neutral-800 dark:text-neutral-200">Place Details</AccordionTrigger>
<AccordionContent>
<div className="px-4 space-y-4 max-h-64 overflow-y-auto">
{result.results.map((place: any, placeIndex: number) => (
<PlaceDetails key={placeIndex} place={place} />
))}
</div>
</AccordionContent>
</AccordionItem>
</Accordion>
</CardContent>
</Card>
<MapContainer
title={`Nearby ${args.type ? args.type.charAt(0).toUpperCase() + args.type.slice(1) + 's' : 'Places'}`}
center={result.center}
places={result.results}
loading={isLoading}
/>
);
}
@ -973,7 +929,19 @@ GPT-4o has been re-enabled! You can use it by selecting the model from the dropd
);
}
return <FindPlaceResult result={result} />;
const place = result.candidates[0];
return (
<MapContainer
title={place.name}
center={place.geometry.location}
places={[{
name: place.name,
location: place.geometry.location,
rating: place.rating,
vicinity: place.formatted_address
}]}
/>
);
}
if (toolInvocation.toolName === 'text_search') {
@ -1004,7 +972,18 @@ GPT-4o has been re-enabled! You can use it by selecting the model from the dropd
);
}
return <TextSearchResult result={result} />;
const centerLocation = result.results[0]?.geometry?.location;
return (
<MapContainer
title="Search Results"
center={centerLocation}
places={result.results.map((place: any) => ({
name: place.name,
location: place.geometry.location,
vicinity: place.formatted_address
}))}
/>
);
}
if (toolInvocation.toolName === 'get_weather_data') {
@ -1091,6 +1070,14 @@ GPT-4o has been re-enabled! You can use it by selecting the model from the dropd
Images
</TabsTrigger>
)}
{result?.chart && (
<TabsTrigger
value="visualization"
className="px-4 py-2 text-sm data-[state=active]:bg-white dark:data-[state=active]:bg-neutral-800 data-[state=active]:border-b data-[state=active]:border-blue-500 rounded-none shadow-sm"
>
Visualization
</TabsTrigger>
)}
</TabsList>
<TabsContent value="code" className="p-0 m-0 rounded-none">
<div className="relative">
@ -1178,6 +1165,19 @@ GPT-4o has been re-enabled! You can use it by selecting the model from the dropd
</div>
</TabsContent>
)}
{result?.chart && (
<TabsContent value="visualization" className="p-4 m-0 bg-white dark:bg-neutral-800">
<InteractiveChart
type={result.chart.type as 'bar' | 'line'}
title={result.chart.title}
xLabel={result.chart.x_label}
yLabel={result.chart.y_label}
xUnit={result.chart.x_unit}
yUnit={result.chart.y_unit}
elements={result.chart.elements}
/>
</TabsContent>
)}
</Tabs>
</div>
</AccordionContent>

View File

@ -0,0 +1,219 @@
// components/interactive-charts.tsx
import React from 'react';
import ReactECharts from 'echarts-for-react';
import * as echarts from 'echarts';
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { useTheme } from 'next-themes';
interface BaseChartProps {
title: string;
xLabel?: string;
yLabel?: string;
xUnit?: string | null;
yUnit?: string | null;
x_ticks?: (number | string)[];
x_tick_labels?: string[];
x_scale?: string;
y_ticks?: (number | string)[];
y_tick_labels?: string[];
y_scale?: string;
}
type BarChartElement = {
label: string;
group: string;
value: number;
};
type PointData = {
label: string;
points: [number | string, number | string][];
};
interface ChartProps extends BaseChartProps {
type: 'bar' | 'line';
elements: BarChartElement[] | PointData[];
}
const InteractiveChart: React.FC<ChartProps> = ({
type,
title,
xLabel = '',
yLabel = '',
xUnit = '',
yUnit = '',
elements,
x_ticks,
x_tick_labels,
x_scale = 'value',
y_ticks,
y_tick_labels,
y_scale = 'value',
}) => {
const { theme } = useTheme();
const getChartOptions = () => {
if (!elements || elements.length === 0) {
return {};
}
const textColor = theme === 'dark' ? '#e5e5e5' : '#171717';
const axisLineColor = theme === 'dark' ? '#404040' : '#e5e5e5';
if (type === 'line') {
const lineElements = elements as PointData[];
const xAxisType = x_scale === 'datetime' ? 'time' : x_scale;
const series = lineElements.map(el => ({
name: el.label,
type: 'line',
data: el.points.map(point => {
const xValue =
xAxisType === 'time'
? new Date(point[0] as string).getTime()
: point[0];
return [xValue, point[1]];
}),
smooth: true,
}));
return {
title: {
text: title || '',
textStyle: { color: textColor },
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
},
},
legend: {
data: lineElements.map(el => el.label),
textStyle: { color: textColor },
},
xAxis: {
type: xAxisType,
name: xLabel,
nameTextStyle: { color: textColor },
axisLabel: {
color: textColor,
formatter: (value: number) => {
if (xAxisType === 'time') {
return echarts.format.formatTime('yyyy-MM', value);
}
return xUnit ? `${value} ${xUnit}` : `${value}`;
},
},
axisLine: { lineStyle: { color: axisLineColor } },
},
yAxis: {
type: y_scale,
name: yLabel,
nameTextStyle: { color: textColor },
axisLabel: {
color: textColor,
formatter: (value: number) =>
yUnit ? `${value} ${yUnit}` : `${value}`,
},
axisLine: { lineStyle: { color: axisLineColor } },
...(y_ticks && {
min: Math.min(...(y_ticks as number[])),
max: Math.max(...(y_ticks as number[])),
}),
},
series,
};
} else if (type === 'bar') {
const barElements = elements as BarChartElement[];
const groups = Array.from(new Set(barElements.map(el => el.group))).filter(Boolean);
const labels = Array.from(new Set(barElements.map(el => el.label))).filter(Boolean);
const series = groups.map(group => ({
name: group,
type: 'bar',
data: labels.map(label => {
const el = barElements.find(e => e.group === group && e.label === label);
return el ? el.value : 0;
}),
}));
return {
title: {
text: title || '',
textStyle: { color: textColor },
},
tooltip: { trigger: 'axis' },
legend: {
data: groups,
textStyle: { color: textColor },
},
xAxis: {
type: 'category',
data: labels,
name: xLabel,
nameTextStyle: { color: textColor },
axisLabel: { color: textColor },
axisLine: { lineStyle: { color: axisLineColor } },
},
yAxis: {
type: 'value',
name: yLabel,
nameTextStyle: { color: textColor },
axisLabel: {
color: textColor,
formatter: (value: number) =>
yUnit ? `${value} ${yUnit}` : value.toString(),
},
axisLine: { lineStyle: { color: axisLineColor } },
...(y_ticks && {
min: Math.min(...(y_ticks as number[])),
max: Math.max(...(y_ticks as number[])),
}),
},
series,
};
}
return {};
};
const options = getChartOptions();
if (!options || Object.keys(options).length === 0) {
return (
<Card className="w-full bg-white dark:bg-neutral-800">
<CardHeader>
<CardTitle className="text-neutral-800 dark:text-neutral-200">
{title || 'Chart'}
</CardTitle>
</CardHeader>
<CardContent>
<div className="text-neutral-600 dark:text-neutral-400">
No data available to display the chart.
</div>
</CardContent>
</Card>
);
}
return (
<Card className="w-full bg-white dark:bg-neutral-800">
<CardHeader>
<CardTitle className="text-neutral-800 dark:text-neutral-200">
{title || 'Chart'}
</CardTitle>
</CardHeader>
<CardContent>
<ReactECharts
option={options}
style={{ height: '400px', width: '100%' }}
/>
</CardContent>
</Card>
);
};
export default InteractiveChart;

View File

@ -1,93 +1,112 @@
import React, { useRef, useState, useEffect, useCallback, memo } from 'react';
import { Card, CardHeader, CardContent, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import React, { useEffect, useRef, useState } from 'react';
import mapboxgl from 'mapbox-gl';
import 'mapbox-gl/dist/mapbox-gl.css';
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";
import { Badge } from "@/components/ui/badge";
import { MapPin, Star } from 'lucide-react';
import { Skeleton } from '@/components/ui/skeleton';
import { Skeleton } from "@/components/ui/skeleton";
const isValidCoordinate = (coord: number) => {
return typeof coord === 'number' && !isNaN(coord) && isFinite(coord);
};
mapboxgl.accessToken = process.env.NEXT_PUBLIC_MAPBOX_TOKEN || '';
const loadGoogleMapsScript = (callback: () => void) => {
if (window.google && window.google.maps) {
callback();
return;
interface Location {
lat: number;
lng: number;
}
const existingScript = document.getElementById('googleMapsScript');
if (existingScript) {
existingScript.remove();
interface Place {
name: string;
location: Location;
vicinity?: string;
rating?: number;
user_ratings_total?: number;
}
window.initMap = callback;
const script = document.createElement('script');
script.id = 'googleMapsScript';
script.src = `https://maps.googleapis.com/maps/api/js?key=${process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY}&libraries=places,marker&callback=initMap`;
script.async = true;
script.defer = true;
document.head.appendChild(script);
};
interface MapProps {
center: Location;
places?: Place[];
zoom?: number;
}
const MapComponent = React.memo(({ center, places }: { center: { lat: number; lng: number }, places: any[] }) => {
const mapRef = useRef<HTMLDivElement>(null);
const MapComponent = React.memo(({ center, places = [], zoom = 14 }: MapProps) => {
const mapContainer = useRef<HTMLDivElement>(null);
const map = useRef<mapboxgl.Map | null>(null);
const markers = useRef<mapboxgl.Marker[]>([]);
const [mapError, setMapError] = useState<string | null>(null);
const googleMapRef = useRef<google.maps.Map | null>(null);
const markersRef = useRef<google.maps.marker.AdvancedMarkerElement[]>([]);
const initializeMap = useCallback(async () => {
if (mapRef.current && isValidCoordinate(center.lat) && isValidCoordinate(center.lng)) {
const { Map } = await google.maps.importLibrary("maps") as google.maps.MapsLibrary;
const { AdvancedMarkerElement } = await google.maps.importLibrary("marker") as google.maps.MarkerLibrary;
if (!googleMapRef.current) {
googleMapRef.current = new Map(mapRef.current, {
center: center,
zoom: 14,
mapId: "347ff92e0c7225cf",
});
} else {
googleMapRef.current.setCenter(center);
}
markersRef.current.forEach(marker => marker.map = null);
markersRef.current = [];
places.forEach((place) => {
if (isValidCoordinate(place.location.lat) && isValidCoordinate(place.location.lng)) {
const marker = new AdvancedMarkerElement({
map: googleMapRef.current,
position: place.location,
title: place.name,
});
markersRef.current.push(marker);
}
});
} else {
setMapError('Invalid coordinates provided');
}
}, [center, places]);
useEffect(() => {
loadGoogleMapsScript(() => {
if (!mapContainer.current) return;
try {
initializeMap();
} catch (error) {
console.error('Error initializing map:', error);
setMapError('Failed to initialize Google Maps');
}
map.current = new mapboxgl.Map({
container: mapContainer.current,
style: 'mapbox://styles/mapbox/streets-v12',
center: [center.lng, center.lat],
zoom: zoom
});
// Add navigation control
map.current.addControl(new mapboxgl.NavigationControl(), 'top-right');
// Clean up markers when component unmounts
return () => {
markersRef.current.forEach(marker => marker.map = null);
markers.current.forEach(marker => marker.remove());
map.current?.remove();
};
}, [initializeMap]);
} catch (error) {
console.error('Error initializing map:', error);
setMapError('Failed to initialize map');
}
}, [center.lat, center.lng, zoom]);
useEffect(() => {
if (!map.current) return;
// Update center when it changes
map.current.flyTo({
center: [center.lng, center.lat],
essential: true
});
// Clear existing markers
markers.current.forEach(marker => marker.remove());
markers.current = [];
// Add new markers
places.forEach(place => {
const el = document.createElement('div');
el.className = 'marker';
el.innerHTML = '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path><circle cx="12" cy="10" r="3"></circle></svg>';
el.style.color = 'hsl(var(--primary))';
el.style.width = '24px';
el.style.height = '24px';
el.style.cursor = 'pointer';
const marker = new mapboxgl.Marker(el)
.setLngLat([place.location.lng, place.location.lat])
.setPopup(
new mapboxgl.Popup({ offset: 25 })
.setHTML(
`<strong>${place.name}</strong>${place.rating ?
`<br>Rating: ${place.rating} ⭐ (${place.user_ratings_total} reviews)` :
''}`
)
)
.addTo(map.current!);
markers.current.push(marker);
});
}, [center, places]);
if (mapError) {
return <div className="h-64 flex items-center justify-center bg-neutral-100 dark:bg-neutral-800 text-neutral-800 dark:text-neutral-200">{mapError}</div>;
return (
<div className="h-64 flex items-center justify-center bg-neutral-100 dark:bg-neutral-800 text-neutral-800 dark:text-neutral-200">
{mapError}
</div>
);
}
return <div ref={mapRef} className="w-full h-64" />;
return <div ref={mapContainer} className="w-full h-64" />;
});
MapComponent.displayName = 'MapComponent';
@ -96,13 +115,15 @@ const MapSkeleton = () => (
<Skeleton className="w-full h-64 bg-neutral-200 dark:bg-neutral-700" />
);
const PlaceDetails = ({ place }: { place: any }) => (
const PlaceDetails = ({ place }: { place: Place }) => (
<div className="flex justify-between items-start py-2">
<div>
<h4 className="font-semibold text-neutral-800 dark:text-neutral-200">{place.name}</h4>
{place.vicinity && (
<p className="text-sm text-neutral-600 dark:text-neutral-400 max-w-[200px]" title={place.vicinity}>
{place.vicinity}
</p>
)}
</div>
{place.rating && (
<Badge variant="secondary" className="flex items-center bg-neutral-200 dark:bg-neutral-700 text-neutral-800 dark:text-neutral-200">
@ -113,95 +134,56 @@ const PlaceDetails = ({ place }: { place: any }) => (
</div>
);
const MapEmbed = memo(({ location, zoom = 15 }: { location: string, zoom?: number }) => {
const apiKey = process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY;
const mapUrl = `https://www.google.com/maps/embed/v1/place?key=${apiKey}&q=${encodeURIComponent(location)}&zoom=${zoom}`;
interface MapContainerProps {
title: string;
center: Location;
places?: Place[];
loading?: boolean;
}
const MapContainer: React.FC<MapContainerProps> = ({ title, center, places = [], loading = false }) => {
if (loading) {
return (
<div className="aspect-video w-full">
<iframe
width="100%"
height="100%"
style={{ border: 0 }}
loading="lazy"
allowFullScreen
referrerPolicy="no-referrer-when-downgrade"
src={mapUrl}
className='rounded-xl'
></iframe>
</div>
);
});
MapEmbed.displayName = 'MapEmbed';
const FindPlaceResult = memo(({ result }: { result: any }) => {
const place = result.candidates[0];
const location = `${place.geometry.location.lat},${place.geometry.location.lng}`;
return (
<Card className="w-full my-4 overflow-hidden shadow-none bg-white dark:bg-neutral-800 border-neutral-200 dark:border-neutral-700">
<Card className="w-full my-4 bg-white dark:bg-neutral-800 border-neutral-200 dark:border-neutral-700">
<CardHeader>
<CardTitle className="flex items-center gap-2 text-neutral-800 dark:text-neutral-100">
<MapPin className="h-5 w-5 text-primary" />
<span>{place.name}</span>
</CardTitle>
<Skeleton className="h-6 w-3/4 bg-neutral-200 dark:bg-neutral-700" />
</CardHeader>
<CardContent>
<MapEmbed location={location} />
<div className="mt-4 space-y-2 text-neutral-800 dark:text-neutral-200">
<p><strong>Address:</strong> {place.formatted_address}</p>
{place.rating && (
<div className="flex items-center">
<strong className="mr-2">Rating:</strong>
<Badge variant="secondary" className="flex items-center bg-neutral-200 dark:bg-neutral-700 text-neutral-800 dark:text-neutral-200">
<Star className="h-3 w-3 mr-1 text-yellow-400" />
{place.rating}
</Badge>
</div>
)}
{place.opening_hours && (
<p><strong>Open now:</strong> {place.opening_hours.open_now ? 'Yes' : 'No'}</p>
)}
</div>
<CardContent className="p-0 rounded-t-none rounded-b-xl">
<MapSkeleton />
</CardContent>
</Card>
);
});
FindPlaceResult.displayName = 'FindPlaceResult';
const TextSearchResult = React.memo(({ result }: { result: any }) => {
const centerLocation = result.results[0]?.geometry?.location;
const mapLocation = centerLocation ? `${centerLocation.lat},${centerLocation.lng}` : '';
}
return (
<Card className="w-full my-4 overflow-hidden shadow-none bg-white dark:bg-neutral-800 border-neutral-200 dark:border-neutral-700">
<Card className="w-full my-4 overflow-hidden bg-white dark:bg-neutral-800 border-neutral-200 dark:border-neutral-700">
<CardHeader>
<CardTitle className="flex items-center gap-2 text-neutral-800 dark:text-neutral-100">
<MapPin className="h-5 w-5 text-primary" />
<span>Text Search Results</span>
<span>{title}</span>
</CardTitle>
</CardHeader>
<CardContent>
{mapLocation && <MapComponent center={centerLocation} places={result.results} />}
<Accordion type="single" collapsible className="w-full mt-4">
<CardContent className="p-0">
<MapComponent center={center} places={places} />
{places.length > 0 && (
<Accordion type="single" collapsible className="w-full">
<AccordionItem value="place-details">
<AccordionTrigger className="text-neutral-800 dark:text-neutral-200">Place Details</AccordionTrigger>
<AccordionTrigger className="px-4 text-neutral-800 dark:text-neutral-200">
Place Details
</AccordionTrigger>
<AccordionContent>
<div className="space-y-4 max-h-64 overflow-y-auto">
{result.results.map((place: any, index: number) => (
<div className="px-4 space-y-4 max-h-64 overflow-y-auto">
{places.map((place, index) => (
<PlaceDetails key={index} place={place} />
))}
</div>
</AccordionContent>
</AccordionItem>
</Accordion>
)}
</CardContent>
</Card>
);
});
};
TextSearchResult.displayName = 'TextSearchResult';
export { MapComponent, MapSkeleton, FindPlaceResult, TextSearchResult };
export { MapComponent, MapSkeleton, MapContainer, PlaceDetails };

View File

@ -23,8 +23,9 @@ interface ModelSwitcherProps {
}
const models = [
{ value: "azure:gpt4o-mini", label: "GPT-4o Mini", icon: Zap, description: "High speed, good quality", color: "emerald" },
{ value: "anthropic:claude-3-5-sonnet-latest", label: "Claude 3.5 Sonnet (New)", icon: Sparkles, description: "High quality, lower speed", color: "indigo" },
{ value: "azure:gpt4o-mini", label: "GPT-4o Mini", icon: Zap, description: "God speed, good quality", color: "emerald" },
{ value: "anthropic:claude-3-5-haiku-20241022", label: "Claude 3.5 Haiku", icon: Sparkles, description: "Good quality, high speed", color: "orange" },
{ value: "anthropic:claude-3-5-sonnet-latest", label: "Claude 3.5 Sonnet (New)", icon: Sparkles, description: "High quality, good speed", color: "indigo" },
{ value: "azure:gpt-4o", label: "GPT-4o", icon: Cpu, description: "Higher quality, normal speed", color: "blue" },
];
@ -46,6 +47,10 @@ const getColorClasses = (color: string, isSelected: boolean = false) => {
return isSelected
? `${baseClasses} ${selectedClasses} !bg-blue-500 dark:!bg-blue-600 !text-white hover:!bg-blue-600 dark:hover:!bg-blue-700`
: `${baseClasses} !text-blue-700 dark:!text-blue-300 hover:!bg-blue-200 dark:hover:!bg-blue-800/70`;
case 'orange':
return isSelected
? `${baseClasses} ${selectedClasses} !bg-orange-500 dark:!bg-orange-600 !text-white hover:!bg-orange-600 dark:hover:!bg-orange-700`
: `${baseClasses} !text-orange-700 dark:!text-orange-300 hover:!bg-orange-200 dark:hover:!bg-orange-800/70`;
default:
return isSelected
? `${baseClasses} ${selectedClasses} !bg-neutral-500 dark:!bg-neutral-600 !text-white hover:!bg-neutral-600 dark:hover:!bg-neutral-700`
@ -486,14 +491,14 @@ const FormComponent: React.FC<FormComponentProps> = ({
}}
/>
<div className="absolute left-2 bottom-2">
<div className="absolute left-2 bottom-2 mt-4">
<ModelSwitcher
selectedModel={selectedModel}
setSelectedModel={setSelectedModel}
/>
</div>
<div className="absolute right-2 bottom-2 flex items-center gap-2">
<div className="absolute right-2 bottom-2 flex items-center gap-2 mt-4">
<Button
className="rounded-full p-1.5 h-8 w-8 bg-white dark:bg-neutral-700 text-neutral-700 dark:text-neutral-300 hover:bg-neutral-300 dark:hover:bg-neutral-600"
onClick={(event) => {

View File

@ -9,14 +9,14 @@
"lint": "next lint"
},
"dependencies": {
"@ai-sdk/anthropic": "^0.0.51",
"@ai-sdk/azure": "^0.0.31",
"@ai-sdk/anthropic": "^0.0.55",
"@ai-sdk/azure": "^0.0.51",
"@ai-sdk/cohere": "latest",
"@ai-sdk/google": "^0.0.52",
"@ai-sdk/groq": "^0.0.1",
"@ai-sdk/mistral": "^0.0.41",
"@ai-sdk/openai": "^0.0.58",
"@e2b/code-interpreter": "^0.0.8",
"@e2b/code-interpreter": "^1.0.3",
"@foobar404/wave": "^2.0.5",
"@mendable/firecrawl-js": "^1.4.3",
"@radix-ui/react-accordion": "^1.2.0",
@ -33,18 +33,21 @@
"@radix-ui/react-tooltip": "^1.1.2",
"@tailwindcss/typography": "^0.5.13",
"@types/katex": "^0.16.7",
"@types/mapbox-gl": "^3.4.0",
"@types/unist": "^3.0.3",
"@upstash/ratelimit": "^2.0.3",
"@upstash/redis": "^1.34.0",
"@vercel/analytics": "^1.3.1",
"@vercel/blob": "^0.23.4",
"@vercel/functions": "^1.4.0",
"ai": "latest",
"ai": "^3.4.33",
"anthropic-vertex-ai": "^1.0.0",
"cheerio": "^1.0.0",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"date-fns": "^3.6.0",
"echarts": "^5.5.1",
"echarts-for-react": "^3.0.2",
"embla-carousel-autoplay": "^8.3.0",
"embla-carousel-react": "^8.3.0",
"framer-motion": "^11.3.19",
@ -52,6 +55,7 @@
"highlight.js": "^11.10.0",
"katex": "^0.16.11",
"lucide-react": "^0.424.0",
"mapbox-gl": "^3.7.0",
"marked-react": "^2.0.0",
"next": "^14.2.10",
"next-themes": "^0.3.0",

View File

@ -6,14 +6,14 @@ settings:
dependencies:
'@ai-sdk/anthropic':
specifier: ^0.0.55
version: 0.0.55(zod@3.23.8)
'@ai-sdk/azure':
specifier: ^0.0.51
version: 0.0.51(zod@3.23.8)
'@ai-sdk/azure':
specifier: ^0.0.31
version: 0.0.31(zod@3.23.8)
'@ai-sdk/cohere':
specifier: latest
version: 0.0.25(zod@3.23.8)
version: 0.0.28(zod@3.23.8)
'@ai-sdk/google':
specifier: ^0.0.52
version: 0.0.52(zod@3.23.8)
@ -27,8 +27,8 @@ dependencies:
specifier: ^0.0.58
version: 0.0.58(zod@3.23.8)
'@e2b/code-interpreter':
specifier: ^0.0.8
version: 0.0.8
specifier: ^1.0.3
version: 1.0.3
'@foobar404/wave':
specifier: ^2.0.5
version: 2.0.5
@ -77,6 +77,9 @@ dependencies:
'@types/katex':
specifier: ^0.16.7
version: 0.16.7
'@types/mapbox-gl':
specifier: ^3.4.0
version: 3.4.0
'@types/unist':
specifier: ^3.0.3
version: 3.0.3
@ -96,8 +99,8 @@ dependencies:
specifier: ^1.4.0
version: 1.4.2
ai:
specifier: latest
version: 3.4.18(openai@4.67.2)(react@18.3.1)(svelte@4.2.19)(vue@3.5.11)(zod@3.23.8)
specifier: ^3.4.33
version: 3.4.33(openai@4.67.2)(react@18.3.1)(svelte@4.2.19)(vue@3.5.11)(zod@3.23.8)
anthropic-vertex-ai:
specifier: ^1.0.0
version: 1.0.0(zod@3.23.8)
@ -113,6 +116,12 @@ dependencies:
date-fns:
specifier: ^3.6.0
version: 3.6.0
echarts:
specifier: ^5.5.1
version: 5.5.1
echarts-for-react:
specifier: ^3.0.2
version: 3.0.2(echarts@5.5.1)(react@18.3.1)
embla-carousel-autoplay:
specifier: ^8.3.0
version: 8.3.0(embla-carousel@8.3.0)
@ -134,6 +143,9 @@ dependencies:
lucide-react:
specifier: ^0.424.0
version: 0.424.0(react@18.3.1)
mapbox-gl:
specifier: ^3.7.0
version: 3.7.0
marked-react:
specifier: ^2.0.0
version: 2.0.0(react@18.3.1)
@ -232,37 +244,37 @@ devDependencies:
packages:
/@ai-sdk/anthropic@0.0.51(zod@3.23.8):
resolution: {integrity: sha512-XPLBvdwdMlNAvGMyfsDgrCDXN2Wz7M+wfCJthqiwdiKHmq2jDLGdt0ZCAozgxxW28HVzMfJlFjuyECiA5Le3YA==}
/@ai-sdk/anthropic@0.0.55(zod@3.23.8):
resolution: {integrity: sha512-SIPGu8on4PKl+PIdbjOniT5/AiE82Yw8HOE/W0GEb2bNGq2KhfkjVt5MBhppg+ZRme5w2iexB4bl66eRa2o89g==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
dependencies:
'@ai-sdk/provider': 0.0.24
'@ai-sdk/provider-utils': 1.0.20(zod@3.23.8)
'@ai-sdk/provider': 0.0.26
'@ai-sdk/provider-utils': 1.0.22(zod@3.23.8)
zod: 3.23.8
dev: false
/@ai-sdk/azure@0.0.31(zod@3.23.8):
resolution: {integrity: sha512-LTiv890qHcw3w87l+OOuYqW1HM9+7olS5mpSOriRY2uZxJWr3MGz8MYqJu2jGNajNKi4j64GsaOuNK69k8KXjw==}
/@ai-sdk/azure@0.0.51(zod@3.23.8):
resolution: {integrity: sha512-DMPuWURdgoweDlSLTj6o3Yx6+hnfr9idvHaTBwgPY+mayvEwlLZp3l08juMn/d/gKgHheQpUEgCQNhCzk6ZJ5w==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
dependencies:
'@ai-sdk/openai': 0.0.53(zod@3.23.8)
'@ai-sdk/provider': 0.0.21
'@ai-sdk/provider-utils': 1.0.16(zod@3.23.8)
'@ai-sdk/openai': 0.0.71(zod@3.23.8)
'@ai-sdk/provider': 0.0.26
'@ai-sdk/provider-utils': 1.0.22(zod@3.23.8)
zod: 3.23.8
dev: false
/@ai-sdk/cohere@0.0.25(zod@3.23.8):
resolution: {integrity: sha512-i7wraTa9/Qmozhw/E5OX+TNIYcPYE7higmCiYvknYyfGTc2XjnVaB2zyIfmbw0TgL+2m3PbVk75vEL5zG1ickQ==}
/@ai-sdk/cohere@0.0.28(zod@3.23.8):
resolution: {integrity: sha512-aWavC7PuC5AcDcwTBcvx2ZemudtjPaZvLDmcVjiIhzvvW2+zoHoWmERD8CtSWIMlQp/vjdTcwNhSXTOqfxm27A==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
dependencies:
'@ai-sdk/provider': 0.0.24
'@ai-sdk/provider-utils': 1.0.20(zod@3.23.8)
'@ai-sdk/provider': 0.0.26
'@ai-sdk/provider-utils': 1.0.22(zod@3.23.8)
zod: 3.23.8
dev: false
@ -300,17 +312,6 @@ packages:
zod: 3.23.8
dev: false
/@ai-sdk/openai@0.0.53(zod@3.23.8):
resolution: {integrity: sha512-Wm4+EYG2Zl5WmhvZJrLhrBY+C46FEQmDjQ9ZB5h2DvRoJZNKtNiVNFMEQuyBK7QwivvlCSMJkPRBfFcbJgNLMQ==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
dependencies:
'@ai-sdk/provider': 0.0.21
'@ai-sdk/provider-utils': 1.0.16(zod@3.23.8)
zod: 3.23.8
dev: false
/@ai-sdk/openai@0.0.58(zod@3.23.8):
resolution: {integrity: sha512-Eao1L0vzfXdymgvc5FDHwV2g2A7BCWml1cShNA+wliY1RL7NNREGcuQvBDNoggB9PM24fawzZyk0ZJ5jlo9Q0w==}
engines: {node: '>=18'}
@ -322,19 +323,14 @@ packages:
zod: 3.23.8
dev: false
/@ai-sdk/provider-utils@1.0.16(zod@3.23.8):
resolution: {integrity: sha512-8Nd8vIkGTIthhfgJEdP9KyMlykehBNP/1J47eMC3vQqYgJV6r5Bgvl3LFVfWi9KzamiD8tp9nU2NJKTeo4MH/A==}
/@ai-sdk/openai@0.0.71(zod@3.23.8):
resolution: {integrity: sha512-ds7u3sWEnKyHxM3lAL9xTs72228HEKcPZCAEFaxmgrexKPJe2tyLBtvS/Kg39SPKPtY9EeaKqi/nbx1AmnXK6A==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
peerDependenciesMeta:
zod:
optional: true
dependencies:
'@ai-sdk/provider': 0.0.21
eventsource-parser: 1.1.2
nanoid: 3.3.6
secure-json-parse: 2.7.0
'@ai-sdk/provider': 0.0.26
'@ai-sdk/provider-utils': 1.0.22(zod@3.23.8)
zod: 3.23.8
dev: false
@ -402,11 +398,20 @@ packages:
zod: 3.23.8
dev: false
/@ai-sdk/provider@0.0.21:
resolution: {integrity: sha512-9j95uaPRxwYkzQdkl4XO/MmWWW5c5vcVSXtqvALpD9SMB9fzH46dO3UN4VbOJR2J3Z84CZAqgZu5tNlkptT9qQ==}
/@ai-sdk/provider-utils@1.0.22(zod@3.23.8):
resolution: {integrity: sha512-YHK2rpj++wnLVc9vPGzGFP3Pjeld2MwhKinetA0zKXOoHAT/Jit5O8kZsxcSlJPu9wvcGT1UGZEjZrtO7PfFOQ==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
peerDependenciesMeta:
zod:
optional: true
dependencies:
json-schema: 0.4.0
'@ai-sdk/provider': 0.0.26
eventsource-parser: 1.1.2
nanoid: 3.3.7
secure-json-parse: 2.7.0
zod: 3.23.8
dev: false
/@ai-sdk/provider@0.0.22:
@ -430,11 +435,18 @@ packages:
json-schema: 0.4.0
dev: false
/@ai-sdk/react@0.0.64(react@18.3.1)(zod@3.23.8):
resolution: {integrity: sha512-4LN2vleyA6rYHZ4Rk9CdxnJgaVkNPJDD4Wx1brUhc5RvUxj3TODcm2UwGOR/mxv4pcydtZGELfQQs/i/tkAUCw==}
/@ai-sdk/provider@0.0.26:
resolution: {integrity: sha512-dQkfBDs2lTYpKM8389oopPdQgIU007GQyCbuPPrV+K6MtSII3HBfE0stUIMXUb44L+LK1t6GXPP7wjSzjO6uKg==}
engines: {node: '>=18'}
dependencies:
json-schema: 0.4.0
dev: false
/@ai-sdk/react@0.0.70(react@18.3.1)(zod@3.23.8):
resolution: {integrity: sha512-GnwbtjW4/4z7MleLiW+TOZC2M29eCg1tOUpuEiYFMmFNZK8mkrqM0PFZMo6UsYeUYMWqEOOcPOU9OQVJMJh7IQ==}
engines: {node: '>=18'}
peerDependencies:
react: ^18 || ^19
react: ^18 || ^19 || ^19.0.0-rc
zod: ^3.0.0
peerDependenciesMeta:
react:
@ -442,15 +454,16 @@ packages:
zod:
optional: true
dependencies:
'@ai-sdk/provider-utils': 1.0.20(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.46(zod@3.23.8)
'@ai-sdk/provider-utils': 1.0.22(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.50(zod@3.23.8)
react: 18.3.1
swr: 2.2.5(react@18.3.1)
throttleit: 2.1.0
zod: 3.23.8
dev: false
/@ai-sdk/solid@0.0.50(zod@3.23.8):
resolution: {integrity: sha512-JF+KKOgGAgcROgae6FU+hAtxMRhR896SzwI3H1h5hFOZrjqYeYzemJoKzA5MR5IBnPSK4FzEjunc8G5L67TyzQ==}
/@ai-sdk/solid@0.0.54(zod@3.23.8):
resolution: {integrity: sha512-96KWTVK+opdFeRubqrgaJXoNiDP89gNxFRWUp0PJOotZW816AbhUf4EnDjBjXTLjXL1n0h8tGSE9sZsRkj9wQQ==}
engines: {node: '>=18'}
peerDependencies:
solid-js: ^1.7.7
@ -458,31 +471,31 @@ packages:
solid-js:
optional: true
dependencies:
'@ai-sdk/provider-utils': 1.0.20(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.46(zod@3.23.8)
'@ai-sdk/provider-utils': 1.0.22(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.50(zod@3.23.8)
transitivePeerDependencies:
- zod
dev: false
/@ai-sdk/svelte@0.0.52(svelte@4.2.19)(zod@3.23.8):
resolution: {integrity: sha512-ZGd81ruVuqpOh1Suma+HwBMBywcOV0IUzi96Q3knIoZIz99sVwebSKH8ExMofXm49bQdCTRa73Wn8sTs6QDIYg==}
/@ai-sdk/svelte@0.0.57(svelte@4.2.19)(zod@3.23.8):
resolution: {integrity: sha512-SyF9ItIR9ALP9yDNAD+2/5Vl1IT6kchgyDH8xkmhysfJI6WrvJbtO1wdQ0nylvPLcsPoYu+cAlz1krU4lFHcYw==}
engines: {node: '>=18'}
peerDependencies:
svelte: ^3.0.0 || ^4.0.0
svelte: ^3.0.0 || ^4.0.0 || ^5.0.0
peerDependenciesMeta:
svelte:
optional: true
dependencies:
'@ai-sdk/provider-utils': 1.0.20(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.46(zod@3.23.8)
'@ai-sdk/provider-utils': 1.0.22(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.50(zod@3.23.8)
sswr: 2.1.0(svelte@4.2.19)
svelte: 4.2.19
transitivePeerDependencies:
- zod
dev: false
/@ai-sdk/ui-utils@0.0.46(zod@3.23.8):
resolution: {integrity: sha512-ZG/wneyJG+6w5Nm/hy1AKMuRgjPQToAxBsTk61c9sVPUTaxo+NNjM2MhXQMtmsja2N5evs8NmHie+ExEgpL3cA==}
/@ai-sdk/ui-utils@0.0.50(zod@3.23.8):
resolution: {integrity: sha512-Z5QYJVW+5XpSaJ4jYCCAVG7zIAuKOOdikhgpksneNmKvx61ACFaf98pmOd+xnjahl0pIlc/QIe6O4yVaJ1sEaw==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
@ -490,16 +503,16 @@ packages:
zod:
optional: true
dependencies:
'@ai-sdk/provider': 0.0.24
'@ai-sdk/provider-utils': 1.0.20(zod@3.23.8)
'@ai-sdk/provider': 0.0.26
'@ai-sdk/provider-utils': 1.0.22(zod@3.23.8)
json-schema: 0.4.0
secure-json-parse: 2.7.0
zod: 3.23.8
zod-to-json-schema: 3.23.2(zod@3.23.8)
zod-to-json-schema: 3.23.3(zod@3.23.8)
dev: false
/@ai-sdk/vue@0.0.55(vue@3.5.11)(zod@3.23.8):
resolution: {integrity: sha512-NZ89CeRPO3D9GjI7GmK3vC+YXjsaWi3iCIvxlGqfQYt0JFKcjgM6dfeq8Nkk+qWI9OoxoOhV/yQdqWQKPv3RRg==}
/@ai-sdk/vue@0.0.59(vue@3.5.11)(zod@3.23.8):
resolution: {integrity: sha512-+ofYlnqdc8c4F6tM0IKF0+7NagZRAiqBJpGDJ+6EYhDW8FHLUP/JFBgu32SjxSxC6IKFZxEnl68ZoP/Z38EMlw==}
engines: {node: '>=18'}
peerDependencies:
vue: ^3.3.4
@ -507,8 +520,8 @@ packages:
vue:
optional: true
dependencies:
'@ai-sdk/provider-utils': 1.0.20(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.46(zod@3.23.8)
'@ai-sdk/provider-utils': 1.0.22(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.50(zod@3.23.8)
swrv: 1.0.4(vue@3.5.11)
vue: 3.5.11(typescript@5.6.2)
transitivePeerDependencies:
@ -561,16 +574,33 @@ packages:
to-fast-properties: 2.0.0
dev: false
/@e2b/code-interpreter@0.0.8:
resolution: {integrity: sha512-cKDFY9js9l3MfL71x0IDvaz0mAhvHIurVFnimtFRXNzuV0TxhuFqsauKabet0TMOrcDF3H3trC7pct6mNgRYTA==}
/@bufbuild/protobuf@1.10.0:
resolution: {integrity: sha512-QDdVFLoN93Zjg36NoQPZfsVH9tZew7wKDKyV5qRdj8ntT4wQCOradQjRaTdwMhWUYsgKsvCINKKm87FdEk96Ag==}
dev: false
/@connectrpc/connect-web@1.6.1(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.6.1):
resolution: {integrity: sha512-GVfxQOmt3TtgTaKeXLS/EA2IHa3nHxwe2BCHT7X0Q/0hohM+nP5DDnIItGEjGrGdt3LTTqWqE4s70N4h+qIMlQ==}
peerDependencies:
'@bufbuild/protobuf': ^1.10.0
'@connectrpc/connect': 1.6.1
dependencies:
'@bufbuild/protobuf': 1.10.0
'@connectrpc/connect': 1.6.1(@bufbuild/protobuf@1.10.0)
dev: false
/@connectrpc/connect@1.6.1(@bufbuild/protobuf@1.10.0):
resolution: {integrity: sha512-KchMDNtU4CDTdkyf0qG7ugJ6qHTOR/aI7XebYn3OTCNagaDYWiZUVKgRgwH79yeMkpNgvEUaXSK7wKjaBK9b/Q==}
peerDependencies:
'@bufbuild/protobuf': ^1.10.0
dependencies:
'@bufbuild/protobuf': 1.10.0
dev: false
/@e2b/code-interpreter@1.0.3:
resolution: {integrity: sha512-/dfMagUEytQtwqkab+0glMPCpPvOwhGaUZvOscT/YvxJxaYPswwjIWb3TXa9DeV25XYw//72syT2wo6rGnnCKw==}
engines: {node: '>=18'}
dependencies:
e2b: 0.16.2
isomorphic-ws: 5.0.0(ws@8.18.0)
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
transitivePeerDependencies:
- bufferutil
- utf-8-validate
e2b: 1.0.2
dev: false
/@eslint-community/eslint-utils@4.4.0(eslint@8.57.1):
@ -705,6 +735,38 @@ packages:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.0
/@mapbox/jsonlint-lines-primitives@2.0.2:
resolution: {integrity: sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==}
engines: {node: '>= 0.6'}
dev: false
/@mapbox/mapbox-gl-supported@3.0.0:
resolution: {integrity: sha512-2XghOwu16ZwPJLOFVuIOaLbN0iKMn867evzXFyf0P22dqugezfJwLmdanAgU25ITvz1TvOfVP4jsDImlDJzcWg==}
dev: false
/@mapbox/point-geometry@0.1.0:
resolution: {integrity: sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==}
dev: false
/@mapbox/tiny-sdf@2.0.6:
resolution: {integrity: sha512-qMqa27TLw+ZQz5Jk+RcwZGH7BQf5G/TrutJhspsca/3SHwmgKQ1iq+d3Jxz5oysPVYTGP6aXxCo5Lk9Er6YBAA==}
dev: false
/@mapbox/unitbezier@0.0.1:
resolution: {integrity: sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==}
dev: false
/@mapbox/vector-tile@1.3.1:
resolution: {integrity: sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==}
dependencies:
'@mapbox/point-geometry': 0.1.0
dev: false
/@mapbox/whoots-js@3.1.0:
resolution: {integrity: sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==}
engines: {node: '>=6.0.0'}
dev: false
/@mendable/firecrawl-js@1.5.3(ws@8.18.0):
resolution: {integrity: sha512-SMxQAUMixlc01OzYB3/9YvTGe/Po/v2NZx5ccCO3OKBk9Vdbo4a5i1Var591H1NYDEqNnRJ6se0X/Y/IiLVvtQ==}
dependencies:
@ -1736,6 +1798,16 @@ packages:
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
dev: false
/@types/geojson-vt@3.2.5:
resolution: {integrity: sha512-qDO7wqtprzlpe8FfQ//ClPV9xiuoh2nkIgiouIptON9w5jvD/fA4szvP9GBlDVdJ5dldAl0kX/sy3URbWwLx0g==}
dependencies:
'@types/geojson': 7946.0.14
dev: false
/@types/geojson@7946.0.14:
resolution: {integrity: sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==}
dev: false
/@types/google.maps@3.58.1:
resolution: {integrity: sha512-X9QTSvGJ0nCfMzYOnaVs/k6/4L+7F5uCS+4iUmkLEls6J9S/Phv+m/i3mDeyc49ZBgwab3EFO1HEoBY7k98EGQ==}
dev: true
@ -1760,6 +1832,24 @@ packages:
resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==}
dev: false
/@types/mapbox-gl@3.4.0:
resolution: {integrity: sha512-tbn++Mm94H1kE7W6FF0oVC9rMXHVzDDNUbS7KfBMRF8NV/8csFi+67ytKcZJ4LsrpsJ+8MC6Os6ZinEDCsrunw==}
dependencies:
'@types/geojson': 7946.0.14
dev: false
/@types/mapbox__point-geometry@0.1.4:
resolution: {integrity: sha512-mUWlSxAmYLfwnRBmgYV86tgYmMIICX4kza8YnE/eIlywGe2XoOxlpVnXWwir92xRLjwyarqwpu2EJKD2pk0IUA==}
dev: false
/@types/mapbox__vector-tile@1.3.4:
resolution: {integrity: sha512-bpd8dRn9pr6xKvuEBQup8pwQfD4VUyqO/2deGjfpe6AwC8YRlyEipvefyRJUSiCJTZuCb8Pl1ciVV5ekqJ96Bg==}
dependencies:
'@types/geojson': 7946.0.14
'@types/mapbox__point-geometry': 0.1.4
'@types/pbf': 3.0.5
dev: false
/@types/mdast@4.0.4:
resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==}
dependencies:
@ -1788,6 +1878,10 @@ packages:
dependencies:
undici-types: 6.19.8
/@types/pbf@3.0.5:
resolution: {integrity: sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==}
dev: false
/@types/prop-types@15.7.13:
resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==}
@ -1808,6 +1902,12 @@ packages:
'@types/prop-types': 15.7.13
csstype: 3.1.3
/@types/supercluster@7.1.3:
resolution: {integrity: sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==}
dependencies:
'@types/geojson': 7946.0.14
dev: false
/@types/unist@2.0.11:
resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==}
dev: false
@ -2049,14 +2149,14 @@ packages:
humanize-ms: 1.2.1
dev: false
/ai@3.4.18(openai@4.67.2)(react@18.3.1)(svelte@4.2.19)(vue@3.5.11)(zod@3.23.8):
resolution: {integrity: sha512-dc6rSBDgaRMX4VgTBsUZwEN5tBWMpJd+MJxB05E2cL4ft9mOmQEZNS6yeu4Ci5rUDj4ZhnmvANHrP7td8Ko9Og==}
/ai@3.4.33(openai@4.67.2)(react@18.3.1)(svelte@4.2.19)(vue@3.5.11)(zod@3.23.8):
resolution: {integrity: sha512-plBlrVZKwPoRTmM8+D1sJac9Bq8eaa2jiZlHLZIWekKWI1yMWYZvCCEezY9ASPwRhULYDJB2VhKOBUUeg3S5JQ==}
engines: {node: '>=18'}
peerDependencies:
openai: ^4.42.0
react: ^18 || ^19
react: ^18 || ^19 || ^19.0.0-rc
sswr: ^2.1.0
svelte: ^3.0.0 || ^4.0.0
svelte: ^3.0.0 || ^4.0.0 || ^5.0.0
zod: ^3.0.0
peerDependenciesMeta:
openai:
@ -2070,24 +2170,23 @@ packages:
zod:
optional: true
dependencies:
'@ai-sdk/provider': 0.0.24
'@ai-sdk/provider-utils': 1.0.20(zod@3.23.8)
'@ai-sdk/react': 0.0.64(react@18.3.1)(zod@3.23.8)
'@ai-sdk/solid': 0.0.50(zod@3.23.8)
'@ai-sdk/svelte': 0.0.52(svelte@4.2.19)(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.46(zod@3.23.8)
'@ai-sdk/vue': 0.0.55(vue@3.5.11)(zod@3.23.8)
'@ai-sdk/provider': 0.0.26
'@ai-sdk/provider-utils': 1.0.22(zod@3.23.8)
'@ai-sdk/react': 0.0.70(react@18.3.1)(zod@3.23.8)
'@ai-sdk/solid': 0.0.54(zod@3.23.8)
'@ai-sdk/svelte': 0.0.57(svelte@4.2.19)(zod@3.23.8)
'@ai-sdk/ui-utils': 0.0.50(zod@3.23.8)
'@ai-sdk/vue': 0.0.59(vue@3.5.11)(zod@3.23.8)
'@opentelemetry/api': 1.9.0
eventsource-parser: 1.1.2
json-schema: 0.4.0
jsondiffpatch: 0.6.0
nanoid: 3.3.6
openai: 4.67.2(zod@3.23.8)
react: 18.3.1
secure-json-parse: 2.7.0
svelte: 4.2.19
zod: 3.23.8
zod-to-json-schema: 3.23.2(zod@3.23.8)
zod-to-json-schema: 3.23.3(zod@3.23.8)
transitivePeerDependencies:
- solid-js
- vue
@ -2349,14 +2448,6 @@ packages:
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
dev: false
/bufferutil@4.0.8:
resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==}
engines: {node: '>=6.14.2'}
requiresBuild: true
dependencies:
node-gyp-build: 4.8.2
dev: false
/busboy@1.6.0:
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
engines: {node: '>=10.16.0'}
@ -2438,6 +2529,10 @@ packages:
resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==}
dev: false
/cheap-ruler@4.0.0:
resolution: {integrity: sha512-0BJa8f4t141BYKQyn9NSQt1PguFQXMXwZiA5shfoaBYHAb2fFk2RAX+tiWMoQU+Agtzt3mdt0JtuyshAXqZ+Vw==}
dev: false
/cheerio-select@2.1.0:
resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==}
dependencies:
@ -2543,6 +2638,10 @@ packages:
engines: {node: '>= 12'}
dev: false
/compare-versions@6.1.1:
resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==}
dev: false
/concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
dev: true
@ -2582,6 +2681,10 @@ packages:
engines: {node: '>= 6'}
dev: false
/csscolorparser@1.0.3:
resolution: {integrity: sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==}
dev: false
/cssesc@3.0.0:
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
engines: {node: '>=4'}
@ -2859,19 +2962,20 @@ packages:
domhandler: 5.0.3
dev: false
/e2b@0.16.2:
resolution: {integrity: sha512-xKmVK4ipgVQPJ/uyyrfH9LnaawERRWt8U2UZhdhGfzdL/QU/OpBjuhoIbFCv1Uy6qXV4nIiJ6Nw4MBC4HmXf1g==}
/e2b@1.0.2:
resolution: {integrity: sha512-jChBH34n4ShQlsOCm3ENDtwFqljE6b++C4YC8lTBuN5Go+4uffPyI9GPfDx5nN4Je3+9FLCciRRyCWsqaDWFQQ==}
engines: {node: '>=18'}
dependencies:
isomorphic-ws: 5.0.0(ws@8.18.0)
normalize-path: 3.0.0
openapi-typescript-fetch: 1.1.3
path-browserify: 1.0.1
'@bufbuild/protobuf': 1.10.0
'@connectrpc/connect': 1.6.1(@bufbuild/protobuf@1.10.0)
'@connectrpc/connect-web': 1.6.1(@bufbuild/protobuf@1.10.0)(@connectrpc/connect@1.6.1)
compare-versions: 6.1.1
openapi-fetch: 0.9.8
platform: 1.3.6
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
optionalDependencies:
bufferutil: 4.0.8
utf-8-validate: 6.0.4
dev: false
/earcut@3.0.0:
resolution: {integrity: sha512-41Fs7Q/PLq1SDbqjsgcY7GA42T0jvaCNGXgGtsNdvg+Yv8eIu06bxv4/PoREkZ9nMDNwnUSG9OFB9+yv8eKhDg==}
dev: false
/eastasianwidth@0.2.0:
@ -2883,6 +2987,25 @@ packages:
safe-buffer: 5.2.1
dev: false
/echarts-for-react@3.0.2(echarts@5.5.1)(react@18.3.1):
resolution: {integrity: sha512-DRwIiTzx8JfwPOVgGttDytBqdp5VzCSyMRIxubgU/g2n9y3VLUmF2FK7Icmg/sNVkv4+rktmrLN9w22U2yy3fA==}
peerDependencies:
echarts: ^3.0.0 || ^4.0.0 || ^5.0.0
react: ^15.0.0 || >=16.0.0
dependencies:
echarts: 5.5.1
fast-deep-equal: 3.1.3
react: 18.3.1
size-sensor: 1.0.2
dev: false
/echarts@5.5.1:
resolution: {integrity: sha512-Fce8upazaAXUVUVsjgV6mBnGuqgO+JNDlcgF79Dksy4+wgGpQB2lmYoO4TSweFg/mZITdpGHomw/cNBJZj1icA==}
dependencies:
tslib: 2.3.0
zrender: 5.6.0
dev: false
/embla-carousel-autoplay@8.3.0(embla-carousel@8.3.0):
resolution: {integrity: sha512-h7DFJLf9uQD+XDxr1NwA3/oFIjsnj/iED2RjET5u6/svMec46IbF1CYPhmB5Q/1Fc0WkcvhPpsEsrtVXQLxNzA==}
peerDependencies:
@ -3400,7 +3523,6 @@ packages:
/fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
dev: true
/fast-equals@5.0.1:
resolution: {integrity: sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==}
@ -3591,6 +3713,10 @@ packages:
- supports-color
dev: false
/geojson-vt@4.0.2:
resolution: {integrity: sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==}
dev: false
/get-intrinsic@1.2.4:
resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
engines: {node: '>= 0.4'}
@ -3622,6 +3748,10 @@ packages:
resolve-pkg-maps: 1.0.0
dev: true
/gl-matrix@3.4.3:
resolution: {integrity: sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==}
dev: false
/glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
@ -3724,6 +3854,10 @@ packages:
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
dev: true
/grid-index@1.1.0:
resolution: {integrity: sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==}
dev: false
/gtoken@7.1.0:
resolution: {integrity: sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==}
engines: {node: '>=14.0.0'}
@ -3932,6 +4066,10 @@ packages:
safer-buffer: 2.1.2
dev: false
/ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
dev: false
/ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
@ -4244,20 +4382,12 @@ packages:
/isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
/isomorphic-ws@5.0.0(ws@8.18.0):
resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==}
peerDependencies:
ws: '*'
dependencies:
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
dev: false
/isows@1.0.6(ws@8.18.0):
resolution: {integrity: sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==}
peerDependencies:
ws: '*'
dependencies:
ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4)
ws: 8.18.0
dev: false
/iterator.prototype@1.1.3:
@ -4372,6 +4502,10 @@ packages:
commander: 8.3.0
dev: false
/kdbush@4.0.2:
resolution: {integrity: sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==}
dev: false
/keyv@4.5.4:
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
dependencies:
@ -4468,6 +4602,39 @@ packages:
'@jridgewell/sourcemap-codec': 1.5.0
dev: false
/mapbox-gl@3.7.0:
resolution: {integrity: sha512-dCbVyH1uGobwv6f4QKRv2Z2wuVT/RmspsudK3sTxGRFxZi6Pd2P9axdbVyZpmGddCAREy44pHhvzvO0qgpdKAg==}
dependencies:
'@mapbox/jsonlint-lines-primitives': 2.0.2
'@mapbox/mapbox-gl-supported': 3.0.0
'@mapbox/point-geometry': 0.1.0
'@mapbox/tiny-sdf': 2.0.6
'@mapbox/unitbezier': 0.0.1
'@mapbox/vector-tile': 1.3.1
'@mapbox/whoots-js': 3.1.0
'@types/geojson': 7946.0.14
'@types/geojson-vt': 3.2.5
'@types/mapbox__point-geometry': 0.1.4
'@types/mapbox__vector-tile': 1.3.4
'@types/pbf': 3.0.5
'@types/supercluster': 7.1.3
cheap-ruler: 4.0.0
csscolorparser: 1.0.3
earcut: 3.0.0
geojson-vt: 4.0.2
gl-matrix: 3.4.3
grid-index: 1.1.0
kdbush: 4.0.2
murmurhash-js: 1.0.0
pbf: 3.3.0
potpack: 2.0.0
quickselect: 3.0.0
serialize-to-js: 3.1.2
supercluster: 8.0.1
tinyqueue: 3.0.0
vt-pbf: 3.1.3
dev: false
/markdown-table@3.0.3:
resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==}
dev: false
@ -4999,6 +5166,10 @@ packages:
/ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
/murmurhash-js@1.0.0:
resolution: {integrity: sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==}
dev: false
/mz@2.7.0:
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
dependencies:
@ -5090,11 +5261,6 @@ packages:
whatwg-url: 5.0.0
dev: false
/node-gyp-build@4.8.2:
resolution: {integrity: sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==}
hasBin: true
dev: false
/normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
@ -5205,9 +5371,14 @@ packages:
- encoding
dev: false
/openapi-typescript-fetch@1.1.3:
resolution: {integrity: sha512-smLZPck4OkKMNExcw8jMgrMOGgVGx2N/s6DbKL2ftNl77g5HfoGpZGFy79RBzU/EkaO0OZpwBnslfdBfh7ZcWg==}
engines: {node: '>= 12.0.0', npm: '>= 7.0.0'}
/openapi-fetch@0.9.8:
resolution: {integrity: sha512-zM6elH0EZStD/gSiNlcPrzXcVQ/pZo3BDvC6CDwRDUt1dDzxlshpmQnpD6cZaJ39THaSmwVCxxRrPKNM1hHrDg==}
dependencies:
openapi-typescript-helpers: 0.0.8
dev: false
/openapi-typescript-helpers@0.0.8:
resolution: {integrity: sha512-1eNjQtbfNi5Z/kFhagDIaIRj6qqDzhjNJKz8cmMW0CVdGwT6e1GLbAfgI0d28VTJa1A8jz82jm/4dG8qNoNS8g==}
dev: false
/optionator@0.9.4:
@ -5289,10 +5460,6 @@ packages:
entities: 4.5.0
dev: false
/path-browserify@1.0.1:
resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
dev: false
/path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
@ -5322,6 +5489,14 @@ packages:
engines: {node: '>=8'}
dev: true
/pbf@3.3.0:
resolution: {integrity: sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==}
hasBin: true
dependencies:
ieee754: 1.2.1
resolve-protobuf-schema: 2.1.0
dev: false
/periscopic@3.1.0:
resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==}
dependencies:
@ -5434,6 +5609,10 @@ packages:
picocolors: 1.1.0
source-map-js: 1.2.1
/potpack@2.0.0:
resolution: {integrity: sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==}
dev: false
/prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
@ -5466,6 +5645,10 @@ packages:
resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==}
dev: false
/protocol-buffers-schema@3.6.0:
resolution: {integrity: sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==}
dev: false
/proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
dev: false
@ -5478,6 +5661,10 @@ packages:
/queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
/quickselect@3.0.0:
resolution: {integrity: sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==}
dev: false
/react-dom@18.3.1(react@18.3.1):
resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==}
peerDependencies:
@ -5782,6 +5969,12 @@ packages:
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
dev: true
/resolve-protobuf-schema@2.1.0:
resolution: {integrity: sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==}
dependencies:
protocol-buffers-schema: 3.6.0
dev: false
/resolve@1.22.8:
resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
hasBin: true
@ -5869,6 +6062,11 @@ packages:
hasBin: true
dev: true
/serialize-to-js@3.1.2:
resolution: {integrity: sha512-owllqNuDDEimQat7EPG0tH7JjO090xKNzUtYz6X+Sk2BXDnOCilDdNLwjWeFywG9xkJul1ULvtUQa9O4pUaY0w==}
engines: {node: '>=4.0.0'}
dev: false
/server-only@0.0.1:
resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==}
dev: false
@ -5919,6 +6117,10 @@ packages:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
/size-sensor@1.0.2:
resolution: {integrity: sha512-2NCmWxY7A9pYKGXNBfteo4hy14gWu47rg5692peVMst6lQLPKrVjhY+UTEsPI5ceFRJSl3gVgMYaUi/hKuaiKw==}
dev: false
/slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'}
@ -6107,6 +6309,12 @@ packages:
pirates: 4.0.6
ts-interface-checker: 0.1.13
/supercluster@8.0.1:
resolution: {integrity: sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==}
dependencies:
kdbush: 4.0.2
dev: false
/supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
@ -6222,10 +6430,19 @@ packages:
dependencies:
any-promise: 1.3.0
/throttleit@2.1.0:
resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==}
engines: {node: '>=18'}
dev: false
/tiny-invariant@1.3.3:
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
dev: false
/tinyqueue@3.0.0:
resolution: {integrity: sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==}
dev: false
/to-fast-properties@2.0.0:
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
engines: {node: '>=4'}
@ -6270,6 +6487,10 @@ packages:
strip-bom: 3.0.0
dev: true
/tslib@2.3.0:
resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==}
dev: false
/tslib@2.7.0:
resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==}
dev: false
@ -6471,14 +6692,6 @@ packages:
react: 18.3.1
dev: false
/utf-8-validate@6.0.4:
resolution: {integrity: sha512-xu9GQDeFp+eZ6LnCywXN/zBancWvOpUMzgjLPSjy4BRHSmTelvn2E0DG0o1sTiw5hkCKBHo8rwSKncfRfv2EEQ==}
engines: {node: '>=6.14.2'}
requiresBuild: true
dependencies:
node-gyp-build: 4.8.2
dev: false
/util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
@ -6527,6 +6740,14 @@ packages:
d3-timer: 3.0.1
dev: false
/vt-pbf@3.1.3:
resolution: {integrity: sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==}
dependencies:
'@mapbox/point-geometry': 0.1.0
'@mapbox/vector-tile': 1.3.1
pbf: 3.3.0
dev: false
/vue@3.5.11(typescript@5.6.2):
resolution: {integrity: sha512-/8Wurrd9J3lb72FTQS7gRMNQD4nztTtKPmuDuPuhqXmmpD6+skVjAeahNpVzsuky6Sy9gy7wn8UadqPtt9SQIg==}
peerDependencies:
@ -6656,7 +6877,7 @@ packages:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
dev: true
/ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.4):
/ws@8.18.0:
resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
engines: {node: '>=10.0.0'}
peerDependencies:
@ -6667,9 +6888,6 @@ packages:
optional: true
utf-8-validate:
optional: true
dependencies:
bufferutil: 4.0.8
utf-8-validate: 6.0.4
dev: false
/xtend@4.0.2:
@ -6687,14 +6905,6 @@ packages:
engines: {node: '>=10'}
dev: true
/zod-to-json-schema@3.23.2(zod@3.23.8):
resolution: {integrity: sha512-uSt90Gzc/tUfyNqxnjlfBs8W6WSGpNBv0rVsNxP/BVSMHMKGdthPYff4xtCHYloJGM0CFxFsb3NbC0eqPhfImw==}
peerDependencies:
zod: ^3.23.3
dependencies:
zod: 3.23.8
dev: false
/zod-to-json-schema@3.23.3(zod@3.23.8):
resolution: {integrity: sha512-TYWChTxKQbRJp5ST22o/Irt9KC5nj7CdBKYB/AosCRdj/wxEMvv4NNaj9XVUHDOIp53ZxArGhnw5HMZziPFjog==}
peerDependencies:
@ -6707,6 +6917,12 @@ packages:
resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==}
dev: false
/zrender@5.6.0:
resolution: {integrity: sha512-uzgraf4njmmHAbEUxMJ8Oxg+P3fT04O+9p7gY+wJRVxo8Ge+KmYv0WJev945EH4wFuc4OY2NLXz46FZrWS9xJg==}
dependencies:
tslib: 2.3.0
dev: false
/zwitch@2.0.4:
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
dev: false