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,19 +38,30 @@ 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,
topP: 0.5,
frequencyPenalty: 0,
presencePenalty: 0,
experimental_activeTools: ["get_weather_data","programming", "web_search", "text_translate"],
experimental_activeTools: ["get_weather_data", "programming", "web_search", "text_translate"],
system: `
You are an expert AI web search engine called MiniPerplx, that helps users find information on the internet with no bullshit talks.
Always start with running the tool(s) and then and then only write your response AT ALL COSTS!!
@ -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,207 +1,189 @@
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;
}
interface Place {
name: string;
location: Location;
vicinity?: string;
rating?: number;
user_ratings_total?: number;
}
interface MapProps {
center: Location;
places?: Place[];
zoom?: number;
}
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);
useEffect(() => {
if (!mapContainer.current) return;
try {
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 () => {
markers.current.forEach(marker => marker.remove());
map.current?.remove();
};
} catch (error) {
console.error('Error initializing map:', error);
setMapError('Failed to initialize map');
}
}, [center.lat, center.lng, zoom]);
const existingScript = document.getElementById('googleMapsScript');
if (existingScript) {
existingScript.remove();
}
useEffect(() => {
if (!map.current) return;
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);
};
// Update center when it changes
map.current.flyTo({
center: [center.lng, center.lat],
essential: true
});
const MapComponent = React.memo(({ center, places }: { center: { lat: number; lng: number }, places: any[] }) => {
const mapRef = useRef<HTMLDivElement>(null);
const [mapError, setMapError] = useState<string | null>(null);
const googleMapRef = useRef<google.maps.Map | null>(null);
const markersRef = useRef<google.maps.marker.AdvancedMarkerElement[]>([]);
// Clear existing markers
markers.current.forEach(marker => marker.remove());
markers.current = [];
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;
// 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';
if (!googleMapRef.current) {
googleMapRef.current = new Map(mapRef.current, {
center: center,
zoom: 14,
mapId: "347ff92e0c7225cf",
});
} else {
googleMapRef.current.setCenter(center);
}
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!);
markersRef.current.forEach(marker => marker.map = null);
markersRef.current = [];
markers.current.push(marker);
});
}, [center, places]);
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]);
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>
);
}
useEffect(() => {
loadGoogleMapsScript(() => {
try {
initializeMap();
} catch (error) {
console.error('Error initializing map:', error);
setMapError('Failed to initialize Google Maps');
}
});
return () => {
markersRef.current.forEach(marker => marker.map = null);
};
}, [initializeMap]);
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 ref={mapRef} className="w-full h-64" />;
return <div ref={mapContainer} className="w-full h-64" />;
});
MapComponent.displayName = 'MapComponent';
const MapSkeleton = () => (
<Skeleton className="w-full h-64 bg-neutral-200 dark:bg-neutral-700" />
<Skeleton className="w-full h-64 bg-neutral-200 dark:bg-neutral-700" />
);
const PlaceDetails = ({ place }: { place: any }) => (
<div className="flex justify-between items-start py-2">
<div>
<h4 className="font-semibold text-neutral-800 dark:text-neutral-200">{place.name}</h4>
<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">
<Star className="h-3 w-3 mr-1 text-yellow-400" />
{place.rating} ({place.user_ratings_total})
</Badge>
)}
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">
<Star className="h-3 w-3 mr-1 text-yellow-400" />
{place.rating} ({place.user_ratings_total})
</Badge>
)}
</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>
<Card className="w-full my-4 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>
);
});
}
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">
<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>
</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>
)}
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>{title}</span>
</CardTitle>
</CardHeader>
<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="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">
{places.map((place, index) => (
<PlaceDetails key={index} place={place} />
))}
</div>
</CardContent>
</Card>
);
});
</AccordionContent>
</AccordionItem>
</Accordion>
)}
</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">
<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>
</CardTitle>
</CardHeader>
<CardContent>
{mapLocation && <MapComponent center={centerLocation} places={result.results} />}
<Accordion type="single" collapsible className="w-full mt-4">
<AccordionItem value="place-details">
<AccordionTrigger className="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) => (
<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