This commit is contained in:
MarkLo 2025-12-20 07:41:05 +08:00
parent f837d4a2d0
commit c4fc8904eb
11 changed files with 385 additions and 225 deletions

View File

@ -104,6 +104,7 @@ async def run_analysis(
deep_think_api_key=request.deep_think_api_key or "", deep_think_api_key=request.deep_think_api_key or "",
embedding_base_url=request.embedding_base_url, embedding_base_url=request.embedding_base_url,
embedding_api_key=request.embedding_api_key or "", embedding_api_key=request.embedding_api_key or "",
embedding_model=request.embedding_model or "all-MiniLM-L6-v2",
alpha_vantage_api_key=request.alpha_vantage_api_key or "", alpha_vantage_api_key=request.alpha_vantage_api_key or "",
finmind_api_key=request.finmind_api_key or "", finmind_api_key=request.finmind_api_key or "",
)) ))
@ -166,7 +167,7 @@ async def cleanup_task(task_id: str):
after the user has saved the results locally or to cloud storage. after the user has saved the results locally or to cloud storage.
This helps keep Redis storage clean and reduces memory usage. This helps keep Redis storage clean and reduces memory usage.
Note: Tasks are also automatically cleaned up 10 minutes after Note: Tasks are also automatically cleaned up 1 hour after
completion/failure, so calling this endpoint is optional but recommended. completion/failure, so calling this endpoint is optional but recommended.
Args: Args:

View File

@ -46,9 +46,13 @@ class AnalysisRequest(BaseModel):
deep_think_api_key: Optional[str] = Field(None, description="API Key for Deep Thinking Model", min_length=0) deep_think_api_key: Optional[str] = Field(None, description="API Key for Deep Thinking Model", min_length=0)
embedding_base_url: Optional[str] = Field( embedding_base_url: Optional[str] = Field(
default="https://api.openai.com/v1", default="https://api.openai.com/v1",
description="Base URL for Embedding Model" description="Base URL for Embedding Model (only used for OpenAI embeddings)"
)
embedding_api_key: Optional[str] = Field(None, description="API Key for Embedding Model (only used for OpenAI embeddings)", min_length=0)
embedding_model: Optional[str] = Field(
default="all-MiniLM-L6-v2",
description="Embedding model: 'all-MiniLM-L6-v2' (local, no API key), 'text-embedding-3-small' (OpenAI), etc."
) )
embedding_api_key: Optional[str] = Field(None, description="API Key for Embedding Model", min_length=0)
alpha_vantage_api_key: Optional[str] = Field( alpha_vantage_api_key: Optional[str] = Field(
None, None,
description="Alpha Vantage API Key (optional, for US stock fundamental data)", description="Alpha Vantage API Key (optional, for US stock fundamental data)",

View File

@ -40,7 +40,7 @@ class HybridTaskManager:
self._lock = threading.RLock() self._lock = threading.RLock()
self._cleanup_interval = 3600 # 1 hour self._cleanup_interval = 3600 # 1 hour
self._task_expiry = 86400 # 24 hours for pending/running tasks self._task_expiry = 86400 # 24 hours for pending/running tasks
self._completed_task_expiry = 600 # 10 minutes for completed/failed tasks (auto cleanup) self._completed_task_expiry = 3600 # 1 hour for completed/failed tasks (auto cleanup)
# Check Redis availability on startup # Check Redis availability on startup
if is_redis_available(): if is_redis_available():

View File

@ -50,6 +50,7 @@ class TradingService:
deep_think_api_key: Optional[str] = None, deep_think_api_key: Optional[str] = None,
embedding_base_url: str = "https://api.openai.com/v1", embedding_base_url: str = "https://api.openai.com/v1",
embedding_api_key: Optional[str] = None, embedding_api_key: Optional[str] = None,
embedding_model: str = "all-MiniLM-L6-v2", # Default to local model
alpha_vantage_api_key: Optional[str] = None, alpha_vantage_api_key: Optional[str] = None,
finmind_api_key: Optional[str] = None, # 台灣股市資料 API finmind_api_key: Optional[str] = None, # 台灣股市資料 API
market_type: str = "us", # 市場類型us (美股) 或 tw (台股) market_type: str = "us", # 市場類型us (美股) 或 tw (台股)
@ -132,8 +133,23 @@ class TradingService:
# Note: For non-OpenAI providers, the user MUST provide the specific key if it differs from the shared one. # Note: For non-OpenAI providers, the user MUST provide the specific key if it differs from the shared one.
config["quick_think_api_key"] = quick_think_api_key if quick_think_api_key else openai_api_key config["quick_think_api_key"] = quick_think_api_key if quick_think_api_key else openai_api_key
config["deep_think_api_key"] = deep_think_api_key if deep_think_api_key else openai_api_key config["deep_think_api_key"] = deep_think_api_key if deep_think_api_key else openai_api_key
# Embedding configuration: determine provider based on model name
local_embedding_models = ["all-MiniLM-L6-v2", "all-mpnet-base-v2"]
is_local_embedding = embedding_model in local_embedding_models
if is_local_embedding:
# Local embedding: use sentence-transformers (no API key needed)
config["embedding_provider"] = "local"
config["embedding_model"] = embedding_model
logger.info(f"Using local embedding model: {embedding_model}")
else:
# OpenAI embedding: requires API key
config["embedding_provider"] = "openai"
config["embedding_model"] = embedding_model
config["embedding_base_url"] = normalize_base_url(embedding_base_url) config["embedding_base_url"] = normalize_base_url(embedding_base_url)
config["embedding_api_key"] = embedding_api_key if embedding_api_key else openai_api_key config["embedding_api_key"] = embedding_api_key if embedding_api_key else openai_api_key
logger.info(f"Using OpenAI embedding model: {embedding_model}")
# 根據 market_type 設定資料供應商 # 根據 market_type 設定資料供應商
if market_type in ["twse", "tpex"]: if market_type in ["twse", "tpex"]:

View File

@ -38,6 +38,7 @@ stockstats
eodhd eodhd
langgraph langgraph
chromadb chromadb
sentence-transformers
setuptools setuptools
backtrader backtrader
akshare akshare

View File

@ -52,6 +52,7 @@ const formSchema = z.object({
research_depth: z.number().int().min(1).max(5), research_depth: z.number().int().min(1).max(5),
quick_think_llm: z.string().min(1, "請選擇快速思維模型"), quick_think_llm: z.string().min(1, "請選擇快速思維模型"),
deep_think_llm: z.string().min(1, "請選擇深層思維模型"), deep_think_llm: z.string().min(1, "請選擇深層思維模型"),
embedding_model: z.string().min(1, "請選擇嵌入式模型"),
// Market type selection: us=美股, twse=上市, tpex=上櫃/興櫃 // Market type selection: us=美股, twse=上市, tpex=上櫃/興櫃
market_type: z.enum(["us", "twse", "tpex"]), market_type: z.enum(["us", "twse", "tpex"]),
@ -71,14 +72,14 @@ const formSchema = z.object({
.url("請輸入有效的 URL") .url("請輸入有效的 URL")
.optional() .optional()
.or(z.literal("")), .or(z.literal("")),
quick_think_api_key: z.string().min(1, "請輸入快速思維模型 API Key"), quick_think_api_key: z.string().optional().or(z.literal("")),
deep_think_api_key: z.string().min(1, "請輸入深層思維模型 API Key"), deep_think_api_key: z.string().optional().or(z.literal("")),
embedding_base_url: z embedding_base_url: z
.string() .string()
.url("請輸入有效的 URL") .url("請輸入有效的 URL")
.optional() .optional()
.or(z.literal("")), .or(z.literal("")),
embedding_api_key: z.string().min(1, "請輸入嵌入模型 API Key"), embedding_api_key: z.string().optional().or(z.literal("")), // 本地模型不需要 API Key
alpha_vantage_api_key: z.string().optional().or(z.literal("")), // 選填 alpha_vantage_api_key: z.string().optional().or(z.literal("")), // 選填
finmind_api_key: z.string().optional().or(z.literal("")), // 選填 finmind_api_key: z.string().optional().or(z.literal("")), // 選填
}); });
@ -106,6 +107,7 @@ export function AnalysisForm({ onSubmit, loading = false }: AnalysisFormProps) {
market_type: "us", // 預設美股 market_type: "us", // 預設美股
quick_think_llm: "gpt-5-mini", quick_think_llm: "gpt-5-mini",
deep_think_llm: "gpt-5-mini", deep_think_llm: "gpt-5-mini",
embedding_model: "all-MiniLM-L6-v2", // 預設使用本地開源模型
custom_quick_think_model: "", custom_quick_think_model: "",
custom_deep_think_model: "", custom_deep_think_model: "",
quick_think_base_url: "https://api.openai.com/v1", quick_think_base_url: "https://api.openai.com/v1",
@ -122,9 +124,11 @@ export function AnalysisForm({ onSubmit, loading = false }: AnalysisFormProps) {
// Load API settings from localStorage and update when models change // Load API settings from localStorage and update when models change
const quickThinkLlm = form.watch("quick_think_llm"); const quickThinkLlm = form.watch("quick_think_llm");
const deepThinkLlm = form.watch("deep_think_llm"); const deepThinkLlm = form.watch("deep_think_llm");
const embeddingModel = form.watch("embedding_model");
const marketType = form.watch("market_type"); const marketType = form.watch("market_type");
const isQuickThinkCustom = quickThinkLlm === "custom"; const isQuickThinkCustom = quickThinkLlm === "custom";
const isDeepThinkCustom = deepThinkLlm === "custom"; const isDeepThinkCustom = deepThinkLlm === "custom";
const isLocalEmbedding = ["all-MiniLM-L6-v2", "all-mpnet-base-v2"].includes(embeddingModel);
useEffect(() => { useEffect(() => {
// Use async version to get decrypted API keys // Use async version to get decrypted API keys
@ -169,6 +173,8 @@ export function AnalysisForm({ onSubmit, loading = false }: AnalysisFormProps) {
); );
} }
// 本地模型不需要設定 API Key 和 Base URL
if (!isLocalEmbedding) {
form.setValue( form.setValue(
"embedding_base_url", "embedding_base_url",
savedSettings.custom_base_url || "https://api.openai.com/v1" savedSettings.custom_base_url || "https://api.openai.com/v1"
@ -177,6 +183,10 @@ export function AnalysisForm({ onSubmit, loading = false }: AnalysisFormProps) {
"embedding_api_key", "embedding_api_key",
savedSettings.custom_api_key || savedSettings.openai_api_key savedSettings.custom_api_key || savedSettings.openai_api_key
); );
} else {
form.setValue("embedding_base_url", "");
form.setValue("embedding_api_key", "");
}
form.setValue( form.setValue(
"alpha_vantage_api_key", "alpha_vantage_api_key",
savedSettings.alpha_vantage_api_key || "" savedSettings.alpha_vantage_api_key || ""
@ -186,7 +196,7 @@ export function AnalysisForm({ onSubmit, loading = false }: AnalysisFormProps) {
loadSettings(); loadSettings();
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [quickThinkLlm, deepThinkLlm, isQuickThinkCustom, isDeepThinkCustom]); }, [quickThinkLlm, deepThinkLlm, embeddingModel, isQuickThinkCustom, isDeepThinkCustom, isLocalEmbedding]);
// 當市場類型改變時,更新預設股票代碼和提示 // 當市場類型改變時,更新預設股票代碼和提示
useEffect(() => { useEffect(() => {
@ -253,6 +263,17 @@ export function AnalysisForm({ onSubmit, loading = false }: AnalysisFormProps) {
return; return;
} }
// Validate API keys are set (they come from localStorage/settings)
if (!values.quick_think_api_key) {
alert("請先在右上角「設定」中設定您的 API Key。\n\n快速思維模型需要對應的 API Key 才能運作。");
return;
}
if (!values.deep_think_api_key) {
alert("請先在右上角「設定」中設定您的 API Key。\n\n深層思維模型需要對應的 API Key 才能運作。");
return;
}
const request: AnalysisRequest = { const request: AnalysisRequest = {
...values, ...values,
quick_think_llm: finalQuickThinkLlm, quick_think_llm: finalQuickThinkLlm,
@ -444,8 +465,8 @@ export function AnalysisForm({ onSubmit, loading = false }: AnalysisFormProps) {
/> />
</div> </div>
{/* 第二行:研究深度、快速思維模型、深層思維模型3列) */} {/* 第二行:研究深度、快速思維模型、深層思維模型、嵌入式模型4列) */}
<div className="md:col-span-2 grid grid-cols-1 md:grid-cols-3 gap-6"> <div className="md:col-span-2 grid grid-cols-1 md:grid-cols-4 gap-6">
<FormField <FormField
control={form.control} control={form.control}
name="research_depth" name="research_depth"
@ -764,6 +785,50 @@ export function AnalysisForm({ onSubmit, loading = false }: AnalysisFormProps) {
)} )}
/> />
)} )}
{/* 嵌入式模型 */}
<FormField
control={form.control}
name="embedding_model"
render={({ field }) => (
<FormItem>
<FormLabel></FormLabel>
<Select
onValueChange={field.onChange}
defaultValue={field.value}
>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="選擇嵌入式模型" />
</SelectTrigger>
</FormControl>
<SelectContent>
{/* 本地開源模型 (不需要 API Key) */}
<SelectItem value="all-MiniLM-L6-v2">
🖥 本地: all-MiniLM-L6-v2 ()
</SelectItem>
<SelectItem value="all-mpnet-base-v2">
🖥 本地: all-mpnet-base-v2
</SelectItem>
{/* OpenAI API 模型 (需要 API Key) */}
<SelectItem value="text-embedding-3-small">
OpenAI: text-embedding-3-small
</SelectItem>
<SelectItem value="text-embedding-3-large">
OpenAI: text-embedding-3-large
</SelectItem>
</SelectContent>
</Select>
<FormDescription>
{isLocalEmbedding
? "🆓 本地模型不需 API Key"
: "☁️ 需要 OpenAI API Key"}
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
</div> </div>
</div> </div>

View File

@ -40,12 +40,14 @@ import { useAuth } from "@/contexts/auth-context";
import { getCloudSettings, saveCloudSettings, isCloudSyncEnabled } from "@/lib/user-api"; import { getCloudSettings, saveCloudSettings, isCloudSyncEnabled } from "@/lib/user-api";
const formSchema = z.object({ const formSchema = z.object({
// Required // All API keys are optional - users only need the ones for their selected models
openai_api_key: z.string().min(1, "OpenAI API Key 為必填"), openai_api_key: z.string().optional().or(z.literal("")),
// Optional // Stock market data APIs
alpha_vantage_api_key: z.string().optional().or(z.literal("")), // 美股基本面資料 alpha_vantage_api_key: z.string().optional().or(z.literal("")), // 美股基本面資料
finmind_api_key: z.string().optional().or(z.literal("")), // 台灣股市資料 finmind_api_key: z.string().optional().or(z.literal("")), // 台灣股市資料
// LLM Providers
anthropic_api_key: z.string().optional().or(z.literal("")), anthropic_api_key: z.string().optional().or(z.literal("")),
google_api_key: z.string().optional().or(z.literal("")), google_api_key: z.string().optional().or(z.literal("")),
grok_api_key: z.string().optional().or(z.literal("")), grok_api_key: z.string().optional().or(z.literal("")),
@ -165,27 +167,11 @@ export function ApiSettingsDialog() {
<Form {...form}> <Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4"> <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
{/* Required Section */} {/* 注意事項 */}
<div className="space-y-4"> <div className="space-y-2">
<h3 className="text-lg font-semibold text-primary"></h3> <div className="bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg p-3 text-blue-800 dark:text-blue-300 text-sm">
💡 API使 Claude Claude API
{/* OpenAI API Key */} </div>
<FormField
control={form.control}
name="openai_api_key"
render={({ field }) => (
<FormItem>
<FormLabel>OpenAI API Key *</FormLabel>
<FormControl>
<Input type="password" placeholder="sk-..." {...field} />
</FormControl>
<FormDescription>
OpenAI GPT-4, GPT-5, o4
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
</div> </div>
{/* Stock Market Data APIs Section */} {/* Stock Market Data APIs Section */}
@ -239,13 +225,29 @@ export function ApiSettingsDialog() {
/> />
</div> </div>
{/* Optional LLM Providers Section */} {/* LLM Providers Section */}
<div className="space-y-4 border-t pt-4"> <div className="space-y-4 border-t pt-4">
<h3 className="text-lg font-semibold text-muted-foreground"> <h3 className="text-lg font-semibold text-muted-foreground">
LLM LLM
</h3> </h3>
{/* Anthropic API Key */} {/* OpenAI API Key */}
<FormField
control={form.control}
name="openai_api_key"
render={({ field }) => (
<FormItem>
<FormLabel>OpenAI API Key</FormLabel>
<FormControl>
<Input type="password" placeholder="sk-..." {...field} />
</FormControl>
<FormDescription>
OpenAI GPT-4, GPT-5, o4 OpenAI
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField <FormField
control={form.control} control={form.control}
name="anthropic_api_key" name="anthropic_api_key"

View File

@ -20,6 +20,7 @@ export interface AnalysisRequest {
deep_think_api_key?: string; deep_think_api_key?: string;
embedding_base_url?: string; embedding_base_url?: string;
embedding_api_key?: string; embedding_api_key?: string;
embedding_model?: string; // Embedding model: 'all-MiniLM-L6-v2' (local), 'text-embedding-3-small' (OpenAI), etc.
alpha_vantage_api_key?: string; alpha_vantage_api_key?: string;
finmind_api_key?: string; // 台灣股市資料 API finmind_api_key?: string; // 台灣股市資料 API
} }

View File

@ -64,7 +64,7 @@ importers:
version: 19.2.0 version: 19.2.0
react-day-picker: react-day-picker:
specifier: ^9.11.3 specifier: ^9.11.3
version: 9.12.0(react@19.2.0) version: 9.13.0(react@19.2.0)
react-dom: react-dom:
specifier: 19.2.0 specifier: 19.2.0
version: 19.2.0(react@19.2.0) version: 19.2.0(react@19.2.0)
@ -76,7 +76,7 @@ importers:
version: 10.1.0(@types/react@19.2.7)(react@19.2.0) version: 10.1.0(@types/react@19.2.7)(react@19.2.0)
recharts: recharts:
specifier: ^3.4.1 specifier: ^3.4.1
version: 3.5.1(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react-is@16.13.1)(react@19.2.0)(redux@5.0.1) version: 3.6.0(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react-is@16.13.1)(react@19.2.0)(redux@5.0.1)
rehype-raw: rehype-raw:
specifier: ^7.0.0 specifier: ^7.0.0
version: 7.0.0 version: 7.0.0
@ -95,7 +95,7 @@ importers:
version: 4.1.18 version: 4.1.18
'@types/node': '@types/node':
specifier: ^20 specifier: ^20
version: 20.19.26 version: 20.19.27
'@types/react': '@types/react':
specifier: ^19 specifier: ^19
version: 19.2.7 version: 19.2.7
@ -107,13 +107,13 @@ importers:
version: 1.0.0 version: 1.0.0
baseline-browser-mapping: baseline-browser-mapping:
specifier: ^2.9.2 specifier: ^2.9.2
version: 2.9.6 version: 2.9.11
eslint: eslint:
specifier: ^9 specifier: ^9
version: 9.39.1(jiti@2.6.1) version: 9.39.2(jiti@2.6.1)
eslint-config-next: eslint-config-next:
specifier: 16.0.3 specifier: 16.0.3
version: 16.0.3(@typescript-eslint/parser@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) version: 16.0.3(@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
tailwindcss: tailwindcss:
specifier: ^4 specifier: ^4
version: 4.1.18 version: 4.1.18
@ -235,8 +235,8 @@ packages:
resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/js@9.39.1': '@eslint/js@9.39.2':
resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==} resolution: {integrity: sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@eslint/object-schema@2.1.7': '@eslint/object-schema@2.1.7':
@ -900,8 +900,8 @@ packages:
'@radix-ui/rect@1.1.1': '@radix-ui/rect@1.1.1':
resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==}
'@reduxjs/toolkit@2.11.1': '@reduxjs/toolkit@2.11.2':
resolution: {integrity: sha512-HjhlEREguAyBTGNzRlGNiDHGQ2EjLSPWwdhhpoEqHYy8hWak3Dp6/fU72OfqVsiMb8S6rbfPsWUF24fxpilrVA==} resolution: {integrity: sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==}
peerDependencies: peerDependencies:
react: ^16.9.0 || ^17.0.0 || ^18 || ^19 react: ^16.9.0 || ^17.0.0 || ^18 || ^19
react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0
@ -914,8 +914,8 @@ packages:
'@rtsao/scc@1.1.0': '@rtsao/scc@1.1.0':
resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
'@standard-schema/spec@1.0.0': '@standard-schema/spec@1.1.0':
resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
'@standard-schema/utils@0.3.0': '@standard-schema/utils@0.3.0':
resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==}
@ -1065,8 +1065,8 @@ packages:
'@types/ms@2.1.0': '@types/ms@2.1.0':
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
'@types/node@20.19.26': '@types/node@20.19.27':
resolution: {integrity: sha512-0l6cjgF0XnihUpndDhk+nyD3exio3iKaYROSgvh/qSevPXax3L8p5DBRFjbvalnwatGgHEQn2R88y2fA3g4irg==} resolution: {integrity: sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==}
'@types/react-dom@19.2.3': '@types/react-dom@19.2.3':
resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==}
@ -1085,63 +1085,63 @@ packages:
'@types/use-sync-external-store@0.0.6': '@types/use-sync-external-store@0.0.6':
resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==}
'@typescript-eslint/eslint-plugin@8.49.0': '@typescript-eslint/eslint-plugin@8.50.0':
resolution: {integrity: sha512-JXij0vzIaTtCwu6SxTh8qBc66kmf1xs7pI4UOiMDFVct6q86G0Zs7KRcEoJgY3Cav3x5Tq0MF5jwgpgLqgKG3A==} resolution: {integrity: sha512-O7QnmOXYKVtPrfYzMolrCTfkezCJS9+ljLdKW/+DCvRsc3UAz+sbH6Xcsv7p30+0OwUbeWfUDAQE0vpabZ3QLg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
'@typescript-eslint/parser': ^8.49.0 '@typescript-eslint/parser': ^8.50.0
eslint: ^8.57.0 || ^9.0.0 eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0' typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/parser@8.49.0': '@typescript-eslint/parser@8.50.0':
resolution: {integrity: sha512-N9lBGA9o9aqb1hVMc9hzySbhKibHmB+N3IpoShyV6HyQYRGIhlrO5rQgttypi+yEeKsKI4idxC8Jw6gXKD4THA==} resolution: {integrity: sha512-6/cmF2piao+f6wSxUsJLZjck7OQsYyRtcOZS02k7XINSNlz93v6emM8WutDQSXnroG2xwYlEVHJI+cPA7CPM3Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0' typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/project-service@8.49.0': '@typescript-eslint/project-service@8.50.0':
resolution: {integrity: sha512-/wJN0/DKkmRUMXjZUXYZpD1NEQzQAAn9QWfGwo+Ai8gnzqH7tvqS7oNVdTjKqOcPyVIdZdyCMoqN66Ia789e7g==} resolution: {integrity: sha512-Cg/nQcL1BcoTijEWyx4mkVC56r8dj44bFDvBdygifuS20f3OZCHmFbjF34DPSi07kwlFvqfv/xOLnJ5DquxSGQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
typescript: '>=4.8.4 <6.0.0' typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/scope-manager@8.49.0': '@typescript-eslint/scope-manager@8.50.0':
resolution: {integrity: sha512-npgS3zi+/30KSOkXNs0LQXtsg9ekZ8OISAOLGWA/ZOEn0ZH74Ginfl7foziV8DT+D98WfQ5Kopwqb/PZOaIJGg==} resolution: {integrity: sha512-xCwfuCZjhIqy7+HKxBLrDVT5q/iq7XBVBXLn57RTIIpelLtEIZHXAF/Upa3+gaCpeV1NNS5Z9A+ID6jn50VD4A==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/tsconfig-utils@8.49.0': '@typescript-eslint/tsconfig-utils@8.50.0':
resolution: {integrity: sha512-8prixNi1/6nawsRYxet4YOhnbW+W9FK/bQPxsGB1D3ZrDzbJ5FXw5XmzxZv82X3B+ZccuSxo/X8q9nQ+mFecWA==} resolution: {integrity: sha512-vxd3G/ybKTSlm31MOA96gqvrRGv9RJ7LGtZCn2Vrc5htA0zCDvcMqUkifcjrWNNKXHUU3WCkYOzzVSFBd0wa2w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
typescript: '>=4.8.4 <6.0.0' typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/type-utils@8.49.0': '@typescript-eslint/type-utils@8.50.0':
resolution: {integrity: sha512-KTExJfQ+svY8I10P4HdxKzWsvtVnsuCifU5MvXrRwoP2KOlNZ9ADNEWWsQTJgMxLzS5VLQKDjkCT/YzgsnqmZg==} resolution: {integrity: sha512-7OciHT2lKCewR0mFoBrvZJ4AXTMe/sYOe87289WAViOocEmDjjv8MvIOT2XESuKj9jp8u3SZYUSh89QA4S1kQw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0' typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/types@8.49.0': '@typescript-eslint/types@8.50.0':
resolution: {integrity: sha512-e9k/fneezorUo6WShlQpMxXh8/8wfyc+biu6tnAqA81oWrEic0k21RHzP9uqqpyBBeBKu4T+Bsjy9/b8u7obXQ==} resolution: {integrity: sha512-iX1mgmGrXdANhhITbpp2QQM2fGehBse9LbTf0sidWK6yg/NE+uhV5dfU1g6EYPlcReYmkE9QLPq/2irKAmtS9w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@typescript-eslint/typescript-estree@8.49.0': '@typescript-eslint/typescript-estree@8.50.0':
resolution: {integrity: sha512-jrLdRuAbPfPIdYNppHJ/D0wN+wwNfJ32YTAm10eJVsFmrVpXQnDWBn8niCSMlWjvml8jsce5E/O+86IQtTbJWA==} resolution: {integrity: sha512-W7SVAGBR/IX7zm1t70Yujpbk+zdPq/u4soeFSknWFdXIFuWsBGBOUu/Tn/I6KHSKvSh91OiMuaSnYp3mtPt5IQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
typescript: '>=4.8.4 <6.0.0' typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/utils@8.49.0': '@typescript-eslint/utils@8.50.0':
resolution: {integrity: sha512-N3W7rJw7Rw+z1tRsHZbK395TWSYvufBXumYtEGzypgMUthlg0/hmCImeA8hgO2d2G4pd7ftpxxul2J8OdtdaFA==} resolution: {integrity: sha512-87KgUXET09CRjGCi2Ejxy3PULXna63/bMYv72tCAlDJC3Yqwln0HiFJ3VJMst2+mEtNtZu5oFvX4qJGjKsnAgg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0' typescript: '>=4.8.4 <6.0.0'
'@typescript-eslint/visitor-keys@8.49.0': '@typescript-eslint/visitor-keys@8.50.0':
resolution: {integrity: sha512-LlKaciDe3GmZFphXIc79THF/YYBugZ7FS1pO581E/edlVVNbZKDy93evqmrfQ9/Y4uN0vVhX4iuchq26mK/iiA==} resolution: {integrity: sha512-Xzmnb58+Db78gT/CCj/PVCvK+zxbnsw6F+O1oheYszJbBSdEjVhQi3C/Xttzxgi/GLmpvOggRs1RFpiJ8+c34Q==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
'@ungap/structured-clone@1.3.0': '@ungap/structured-clone@1.3.0':
@ -1336,8 +1336,8 @@ packages:
balanced-match@1.0.2: balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
baseline-browser-mapping@2.9.6: baseline-browser-mapping@2.9.11:
resolution: {integrity: sha512-v9BVVpOTLB59C9E7aSnmIF8h7qRsFpx+A2nugVMTszEOMcfjlZMsXRm4LF23I3Z9AJxc8ANpIvzbzONoX9VJlg==} resolution: {integrity: sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==}
hasBin: true hasBin: true
brace-expansion@1.1.12: brace-expansion@1.1.12:
@ -1371,8 +1371,8 @@ packages:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'} engines: {node: '>=6'}
caniuse-lite@1.0.30001760: caniuse-lite@1.0.30001761:
resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==} resolution: {integrity: sha512-JF9ptu1vP2coz98+5051jZ4PwQgd2ni8A+gYSN7EA7dPKIMf0pDlSUxhdmVOaV3/fYK5uWBkgSXJaRLr4+3A6g==}
ccount@2.0.1: ccount@2.0.1:
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
@ -1572,8 +1572,8 @@ packages:
resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==}
engines: {node: '>=0.12'} engines: {node: '>=0.12'}
es-abstract@1.24.0: es-abstract@1.24.1:
resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} resolution: {integrity: sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
es-define-property@1.0.1: es-define-property@1.0.1:
@ -1584,8 +1584,8 @@ packages:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
es-iterator-helpers@1.2.1: es-iterator-helpers@1.2.2:
resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} resolution: {integrity: sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
es-object-atoms@1.1.1: es-object-atoms@1.1.1:
@ -1604,8 +1604,8 @@ packages:
resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
es-toolkit@1.42.0: es-toolkit@1.43.0:
resolution: {integrity: sha512-SLHIyY7VfDJBM8clz4+T2oquwTQxEzu263AyhVK4jREOAwJ+8eebaa4wM3nlvnAqhDrMm2EsA6hWHaQsMPQ1nA==} resolution: {integrity: sha512-SKCT8AsWvYzBBuUqMk4NPwFlSdqLpJwmy6AP322ERn8W2YLIB6JBXnwMI2Qsh2gfphT3q7EKAxKb23cvFHFwKA==}
escalade@3.2.0: escalade@3.2.0:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
@ -1705,8 +1705,8 @@ packages:
resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
eslint@9.39.1: eslint@9.39.2:
resolution: {integrity: sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==} resolution: {integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@ -2558,8 +2558,8 @@ packages:
queue-microtask@1.2.3: queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
react-day-picker@9.12.0: react-day-picker@9.13.0:
resolution: {integrity: sha512-t8OvG/Zrciso5CQJu5b1A7yzEmebvST+S3pOVQJWxwjjVngyG/CA2htN/D15dLI4uTEuLLkbZyS4YYt480FAtA==} resolution: {integrity: sha512-euzj5Hlq+lOHqI53NiuNhCP8HWgsPf/bBAVijR50hNaY1XwjKjShAnIe8jm8RD2W9IJUvihDIZ+KrmqfFzNhFQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
peerDependencies: peerDependencies:
react: '>=16.8.0' react: '>=16.8.0'
@ -2630,8 +2630,8 @@ packages:
resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
recharts@3.5.1: recharts@3.6.0:
resolution: {integrity: sha512-+v+HJojK7gnEgG6h+b2u7k8HH7FhyFUzAc4+cPrsjL4Otdgqr/ecXzAnHciqlzV1ko064eNcsdzrYOM78kankA==} resolution: {integrity: sha512-L5bjxvQRAe26RlToBAziKUB7whaGKEwD3znoM6fz3DrTowCIC/FnJYnuq1GEzB8Zv2kdTfaxQfi5GoH0tBinyg==}
engines: {node: '>=18'} engines: {node: '>=18'}
peerDependencies: peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
@ -2896,8 +2896,8 @@ packages:
resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
typescript-eslint@8.49.0: typescript-eslint@8.50.0:
resolution: {integrity: sha512-zRSVH1WXD0uXczCXw+nsdjGPUdx4dfrs5VQoHnUWmv1U3oNlAKv4FUNdLDhVUg+gYn+a5hUESqch//Rv5wVhrg==} resolution: {integrity: sha512-Q1/6yNUmCpH94fbgMUMg2/BSAr/6U7GBk61kZTv1/asghQOWOjTlp9K8mixS5NcJmm2creY+UFfGeW/+OcA64A==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies: peerDependencies:
eslint: ^8.57.0 || ^9.0.0 eslint: ^8.57.0 || ^9.0.0
@ -2936,8 +2936,8 @@ packages:
unrs-resolver@1.11.1: unrs-resolver@1.11.1:
resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==}
update-browserslist-db@1.2.2: update-browserslist-db@1.2.3:
resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==} resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
browserslist: '>= 4.21.0' browserslist: '>= 4.21.0'
@ -3151,9 +3151,9 @@ snapshots:
tslib: 2.8.1 tslib: 2.8.1
optional: true optional: true
'@eslint-community/eslint-utils@4.9.0(eslint@9.39.1(jiti@2.6.1))': '@eslint-community/eslint-utils@4.9.0(eslint@9.39.2(jiti@2.6.1))':
dependencies: dependencies:
eslint: 9.39.1(jiti@2.6.1) eslint: 9.39.2(jiti@2.6.1)
eslint-visitor-keys: 3.4.3 eslint-visitor-keys: 3.4.3
'@eslint-community/regexpp@4.12.2': {} '@eslint-community/regexpp@4.12.2': {}
@ -3188,7 +3188,7 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@eslint/js@9.39.1': {} '@eslint/js@9.39.2': {}
'@eslint/object-schema@2.1.7': {} '@eslint/object-schema@2.1.7': {}
@ -3785,9 +3785,9 @@ snapshots:
'@radix-ui/rect@1.1.1': {} '@radix-ui/rect@1.1.1': {}
'@reduxjs/toolkit@2.11.1(react-redux@9.2.0(@types/react@19.2.7)(react@19.2.0)(redux@5.0.1))(react@19.2.0)': '@reduxjs/toolkit@2.11.2(react-redux@9.2.0(@types/react@19.2.7)(react@19.2.0)(redux@5.0.1))(react@19.2.0)':
dependencies: dependencies:
'@standard-schema/spec': 1.0.0 '@standard-schema/spec': 1.1.0
'@standard-schema/utils': 0.3.0 '@standard-schema/utils': 0.3.0
immer: 11.0.1 immer: 11.0.1
redux: 5.0.1 redux: 5.0.1
@ -3799,7 +3799,7 @@ snapshots:
'@rtsao/scc@1.1.0': {} '@rtsao/scc@1.1.0': {}
'@standard-schema/spec@1.0.0': {} '@standard-schema/spec@1.1.0': {}
'@standard-schema/utils@0.3.0': {} '@standard-schema/utils@0.3.0': {}
@ -3929,7 +3929,7 @@ snapshots:
'@types/ms@2.1.0': {} '@types/ms@2.1.0': {}
'@types/node@20.19.26': '@types/node@20.19.27':
dependencies: dependencies:
undici-types: 6.21.0 undici-types: 6.21.0
@ -3947,15 +3947,15 @@ snapshots:
'@types/use-sync-external-store@0.0.6': {} '@types/use-sync-external-store@0.0.6': {}
'@typescript-eslint/eslint-plugin@8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': '@typescript-eslint/eslint-plugin@8.50.0(@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)':
dependencies: dependencies:
'@eslint-community/regexpp': 4.12.2 '@eslint-community/regexpp': 4.12.2
'@typescript-eslint/parser': 8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
'@typescript-eslint/scope-manager': 8.49.0 '@typescript-eslint/scope-manager': 8.50.0
'@typescript-eslint/type-utils': 8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/type-utils': 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
'@typescript-eslint/utils': 8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/utils': 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.49.0 '@typescript-eslint/visitor-keys': 8.50.0
eslint: 9.39.1(jiti@2.6.1) eslint: 9.39.2(jiti@2.6.1)
ignore: 7.0.5 ignore: 7.0.5
natural-compare: 1.4.0 natural-compare: 1.4.0
ts-api-utils: 2.1.0(typescript@5.9.3) ts-api-utils: 2.1.0(typescript@5.9.3)
@ -3963,56 +3963,56 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/parser@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': '@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)':
dependencies: dependencies:
'@typescript-eslint/scope-manager': 8.49.0 '@typescript-eslint/scope-manager': 8.50.0
'@typescript-eslint/types': 8.49.0 '@typescript-eslint/types': 8.50.0
'@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3) '@typescript-eslint/typescript-estree': 8.50.0(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.49.0 '@typescript-eslint/visitor-keys': 8.50.0
debug: 4.4.3 debug: 4.4.3
eslint: 9.39.1(jiti@2.6.1) eslint: 9.39.2(jiti@2.6.1)
typescript: 5.9.3 typescript: 5.9.3
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/project-service@8.49.0(typescript@5.9.3)': '@typescript-eslint/project-service@8.50.0(typescript@5.9.3)':
dependencies: dependencies:
'@typescript-eslint/tsconfig-utils': 8.49.0(typescript@5.9.3) '@typescript-eslint/tsconfig-utils': 8.50.0(typescript@5.9.3)
'@typescript-eslint/types': 8.49.0 '@typescript-eslint/types': 8.50.0
debug: 4.4.3 debug: 4.4.3
typescript: 5.9.3 typescript: 5.9.3
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/scope-manager@8.49.0': '@typescript-eslint/scope-manager@8.50.0':
dependencies: dependencies:
'@typescript-eslint/types': 8.49.0 '@typescript-eslint/types': 8.50.0
'@typescript-eslint/visitor-keys': 8.49.0 '@typescript-eslint/visitor-keys': 8.50.0
'@typescript-eslint/tsconfig-utils@8.49.0(typescript@5.9.3)': '@typescript-eslint/tsconfig-utils@8.50.0(typescript@5.9.3)':
dependencies: dependencies:
typescript: 5.9.3 typescript: 5.9.3
'@typescript-eslint/type-utils@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': '@typescript-eslint/type-utils@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)':
dependencies: dependencies:
'@typescript-eslint/types': 8.49.0 '@typescript-eslint/types': 8.50.0
'@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3) '@typescript-eslint/typescript-estree': 8.50.0(typescript@5.9.3)
'@typescript-eslint/utils': 8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/utils': 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
debug: 4.4.3 debug: 4.4.3
eslint: 9.39.1(jiti@2.6.1) eslint: 9.39.2(jiti@2.6.1)
ts-api-utils: 2.1.0(typescript@5.9.3) ts-api-utils: 2.1.0(typescript@5.9.3)
typescript: 5.9.3 typescript: 5.9.3
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/types@8.49.0': {} '@typescript-eslint/types@8.50.0': {}
'@typescript-eslint/typescript-estree@8.49.0(typescript@5.9.3)': '@typescript-eslint/typescript-estree@8.50.0(typescript@5.9.3)':
dependencies: dependencies:
'@typescript-eslint/project-service': 8.49.0(typescript@5.9.3) '@typescript-eslint/project-service': 8.50.0(typescript@5.9.3)
'@typescript-eslint/tsconfig-utils': 8.49.0(typescript@5.9.3) '@typescript-eslint/tsconfig-utils': 8.50.0(typescript@5.9.3)
'@typescript-eslint/types': 8.49.0 '@typescript-eslint/types': 8.50.0
'@typescript-eslint/visitor-keys': 8.49.0 '@typescript-eslint/visitor-keys': 8.50.0
debug: 4.4.3 debug: 4.4.3
minimatch: 9.0.5 minimatch: 9.0.5
semver: 7.7.3 semver: 7.7.3
@ -4022,20 +4022,20 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/utils@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': '@typescript-eslint/utils@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)':
dependencies: dependencies:
'@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1))
'@typescript-eslint/scope-manager': 8.49.0 '@typescript-eslint/scope-manager': 8.50.0
'@typescript-eslint/types': 8.49.0 '@typescript-eslint/types': 8.50.0
'@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3) '@typescript-eslint/typescript-estree': 8.50.0(typescript@5.9.3)
eslint: 9.39.1(jiti@2.6.1) eslint: 9.39.2(jiti@2.6.1)
typescript: 5.9.3 typescript: 5.9.3
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@typescript-eslint/visitor-keys@8.49.0': '@typescript-eslint/visitor-keys@8.50.0':
dependencies: dependencies:
'@typescript-eslint/types': 8.49.0 '@typescript-eslint/types': 8.50.0
eslint-visitor-keys: 4.2.1 eslint-visitor-keys: 4.2.1
'@ungap/structured-clone@1.3.0': {} '@ungap/structured-clone@1.3.0': {}
@ -4134,7 +4134,7 @@ snapshots:
call-bind: 1.0.8 call-bind: 1.0.8
call-bound: 1.0.4 call-bound: 1.0.4
define-properties: 1.2.1 define-properties: 1.2.1
es-abstract: 1.24.0 es-abstract: 1.24.1
es-object-atoms: 1.1.1 es-object-atoms: 1.1.1
get-intrinsic: 1.3.0 get-intrinsic: 1.3.0
is-string: 1.1.1 is-string: 1.1.1
@ -4144,7 +4144,7 @@ snapshots:
dependencies: dependencies:
call-bind: 1.0.8 call-bind: 1.0.8
define-properties: 1.2.1 define-properties: 1.2.1
es-abstract: 1.24.0 es-abstract: 1.24.1
es-errors: 1.3.0 es-errors: 1.3.0
es-object-atoms: 1.1.1 es-object-atoms: 1.1.1
es-shim-unscopables: 1.1.0 es-shim-unscopables: 1.1.0
@ -4154,7 +4154,7 @@ snapshots:
call-bind: 1.0.8 call-bind: 1.0.8
call-bound: 1.0.4 call-bound: 1.0.4
define-properties: 1.2.1 define-properties: 1.2.1
es-abstract: 1.24.0 es-abstract: 1.24.1
es-errors: 1.3.0 es-errors: 1.3.0
es-object-atoms: 1.1.1 es-object-atoms: 1.1.1
es-shim-unscopables: 1.1.0 es-shim-unscopables: 1.1.0
@ -4163,21 +4163,21 @@ snapshots:
dependencies: dependencies:
call-bind: 1.0.8 call-bind: 1.0.8
define-properties: 1.2.1 define-properties: 1.2.1
es-abstract: 1.24.0 es-abstract: 1.24.1
es-shim-unscopables: 1.1.0 es-shim-unscopables: 1.1.0
array.prototype.flatmap@1.3.3: array.prototype.flatmap@1.3.3:
dependencies: dependencies:
call-bind: 1.0.8 call-bind: 1.0.8
define-properties: 1.2.1 define-properties: 1.2.1
es-abstract: 1.24.0 es-abstract: 1.24.1
es-shim-unscopables: 1.1.0 es-shim-unscopables: 1.1.0
array.prototype.tosorted@1.1.4: array.prototype.tosorted@1.1.4:
dependencies: dependencies:
call-bind: 1.0.8 call-bind: 1.0.8
define-properties: 1.2.1 define-properties: 1.2.1
es-abstract: 1.24.0 es-abstract: 1.24.1
es-errors: 1.3.0 es-errors: 1.3.0
es-shim-unscopables: 1.1.0 es-shim-unscopables: 1.1.0
@ -4186,7 +4186,7 @@ snapshots:
array-buffer-byte-length: 1.0.2 array-buffer-byte-length: 1.0.2
call-bind: 1.0.8 call-bind: 1.0.8
define-properties: 1.2.1 define-properties: 1.2.1
es-abstract: 1.24.0 es-abstract: 1.24.1
es-errors: 1.3.0 es-errors: 1.3.0
get-intrinsic: 1.3.0 get-intrinsic: 1.3.0
is-array-buffer: 3.0.5 is-array-buffer: 3.0.5
@ -4221,7 +4221,7 @@ snapshots:
balanced-match@1.0.2: {} balanced-match@1.0.2: {}
baseline-browser-mapping@2.9.6: {} baseline-browser-mapping@2.9.11: {}
brace-expansion@1.1.12: brace-expansion@1.1.12:
dependencies: dependencies:
@ -4238,11 +4238,11 @@ snapshots:
browserslist@4.28.1: browserslist@4.28.1:
dependencies: dependencies:
baseline-browser-mapping: 2.9.6 baseline-browser-mapping: 2.9.11
caniuse-lite: 1.0.30001760 caniuse-lite: 1.0.30001761
electron-to-chromium: 1.5.267 electron-to-chromium: 1.5.267
node-releases: 2.0.27 node-releases: 2.0.27
update-browserslist-db: 1.2.2(browserslist@4.28.1) update-browserslist-db: 1.2.3(browserslist@4.28.1)
call-bind-apply-helpers@1.0.2: call-bind-apply-helpers@1.0.2:
dependencies: dependencies:
@ -4263,7 +4263,7 @@ snapshots:
callsites@3.1.0: {} callsites@3.1.0: {}
caniuse-lite@1.0.30001760: {} caniuse-lite@1.0.30001761: {}
ccount@2.0.1: {} ccount@2.0.1: {}
@ -4437,7 +4437,7 @@ snapshots:
entities@6.0.1: {} entities@6.0.1: {}
es-abstract@1.24.0: es-abstract@1.24.1:
dependencies: dependencies:
array-buffer-byte-length: 1.0.2 array-buffer-byte-length: 1.0.2
arraybuffer.prototype.slice: 1.0.4 arraybuffer.prototype.slice: 1.0.4
@ -4498,12 +4498,12 @@ snapshots:
es-errors@1.3.0: {} es-errors@1.3.0: {}
es-iterator-helpers@1.2.1: es-iterator-helpers@1.2.2:
dependencies: dependencies:
call-bind: 1.0.8 call-bind: 1.0.8
call-bound: 1.0.4 call-bound: 1.0.4
define-properties: 1.2.1 define-properties: 1.2.1
es-abstract: 1.24.0 es-abstract: 1.24.1
es-errors: 1.3.0 es-errors: 1.3.0
es-set-tostringtag: 2.1.0 es-set-tostringtag: 2.1.0
function-bind: 1.1.2 function-bind: 1.1.2
@ -4538,7 +4538,7 @@ snapshots:
is-date-object: 1.1.0 is-date-object: 1.1.0
is-symbol: 1.1.1 is-symbol: 1.1.1
es-toolkit@1.42.0: {} es-toolkit@1.43.0: {}
escalade@3.2.0: {} escalade@3.2.0: {}
@ -4546,18 +4546,18 @@ snapshots:
escape-string-regexp@5.0.0: {} escape-string-regexp@5.0.0: {}
eslint-config-next@16.0.3(@typescript-eslint/parser@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): eslint-config-next@16.0.3(@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3):
dependencies: dependencies:
'@next/eslint-plugin-next': 16.0.3 '@next/eslint-plugin-next': 16.0.3
eslint: 9.39.1(jiti@2.6.1) eslint: 9.39.2(jiti@2.6.1)
eslint-import-resolver-node: 0.3.9 eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1)) eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-react: 7.37.5(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-react: 7.37.5(eslint@9.39.2(jiti@2.6.1))
eslint-plugin-react-hooks: 7.0.1(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-react-hooks: 7.0.1(eslint@9.39.2(jiti@2.6.1))
globals: 16.4.0 globals: 16.4.0
typescript-eslint: 8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) typescript-eslint: 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
optionalDependencies: optionalDependencies:
typescript: 5.9.3 typescript: 5.9.3
transitivePeerDependencies: transitivePeerDependencies:
@ -4574,33 +4574,33 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1)): eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1)):
dependencies: dependencies:
'@nolyfill/is-core-module': 1.0.39 '@nolyfill/is-core-module': 1.0.39
debug: 4.4.3 debug: 4.4.3
eslint: 9.39.1(jiti@2.6.1) eslint: 9.39.2(jiti@2.6.1)
get-tsconfig: 4.13.0 get-tsconfig: 4.13.0
is-bun-module: 2.0.0 is-bun-module: 2.0.0
stable-hash: 0.0.5 stable-hash: 0.0.5
tinyglobby: 0.2.15 tinyglobby: 0.2.15
unrs-resolver: 1.11.1 unrs-resolver: 1.11.1
optionalDependencies: optionalDependencies:
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1))
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
eslint-module-utils@2.12.1(@typescript-eslint/parser@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)): eslint-module-utils@2.12.1(@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)):
dependencies: dependencies:
debug: 3.2.7 debug: 3.2.7
optionalDependencies: optionalDependencies:
'@typescript-eslint/parser': 8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
eslint: 9.39.1(jiti@2.6.1) eslint: 9.39.2(jiti@2.6.1)
eslint-import-resolver-node: 0.3.9 eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@2.6.1)) eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.2(jiti@2.6.1))
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)): eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1)):
dependencies: dependencies:
'@rtsao/scc': 1.1.0 '@rtsao/scc': 1.1.0
array-includes: 3.1.9 array-includes: 3.1.9
@ -4609,9 +4609,9 @@ snapshots:
array.prototype.flatmap: 1.3.3 array.prototype.flatmap: 1.3.3
debug: 3.2.7 debug: 3.2.7
doctrine: 2.1.0 doctrine: 2.1.0
eslint: 9.39.1(jiti@2.6.1) eslint: 9.39.2(jiti@2.6.1)
eslint-import-resolver-node: 0.3.9 eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@2.6.1)) eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.2(jiti@2.6.1))
hasown: 2.0.2 hasown: 2.0.2
is-core-module: 2.16.1 is-core-module: 2.16.1
is-glob: 4.0.3 is-glob: 4.0.3
@ -4623,13 +4623,13 @@ snapshots:
string.prototype.trimend: 1.0.9 string.prototype.trimend: 1.0.9
tsconfig-paths: 3.15.0 tsconfig-paths: 3.15.0
optionalDependencies: optionalDependencies:
'@typescript-eslint/parser': 8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
transitivePeerDependencies: transitivePeerDependencies:
- eslint-import-resolver-typescript - eslint-import-resolver-typescript
- eslint-import-resolver-webpack - eslint-import-resolver-webpack
- supports-color - supports-color
eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.1(jiti@2.6.1)): eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.2(jiti@2.6.1)):
dependencies: dependencies:
aria-query: 5.3.2 aria-query: 5.3.2
array-includes: 3.1.9 array-includes: 3.1.9
@ -4639,7 +4639,7 @@ snapshots:
axobject-query: 4.1.0 axobject-query: 4.1.0
damerau-levenshtein: 1.0.8 damerau-levenshtein: 1.0.8
emoji-regex: 9.2.2 emoji-regex: 9.2.2
eslint: 9.39.1(jiti@2.6.1) eslint: 9.39.2(jiti@2.6.1)
hasown: 2.0.2 hasown: 2.0.2
jsx-ast-utils: 3.3.5 jsx-ast-utils: 3.3.5
language-tags: 1.0.9 language-tags: 1.0.9
@ -4648,26 +4648,26 @@ snapshots:
safe-regex-test: 1.1.0 safe-regex-test: 1.1.0
string.prototype.includes: 2.0.1 string.prototype.includes: 2.0.1
eslint-plugin-react-hooks@7.0.1(eslint@9.39.1(jiti@2.6.1)): eslint-plugin-react-hooks@7.0.1(eslint@9.39.2(jiti@2.6.1)):
dependencies: dependencies:
'@babel/core': 7.28.5 '@babel/core': 7.28.5
'@babel/parser': 7.28.5 '@babel/parser': 7.28.5
eslint: 9.39.1(jiti@2.6.1) eslint: 9.39.2(jiti@2.6.1)
hermes-parser: 0.25.1 hermes-parser: 0.25.1
zod: 3.25.76 zod: 3.25.76
zod-validation-error: 4.0.2(zod@3.25.76) zod-validation-error: 4.0.2(zod@3.25.76)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
eslint-plugin-react@7.37.5(eslint@9.39.1(jiti@2.6.1)): eslint-plugin-react@7.37.5(eslint@9.39.2(jiti@2.6.1)):
dependencies: dependencies:
array-includes: 3.1.9 array-includes: 3.1.9
array.prototype.findlast: 1.2.5 array.prototype.findlast: 1.2.5
array.prototype.flatmap: 1.3.3 array.prototype.flatmap: 1.3.3
array.prototype.tosorted: 1.1.4 array.prototype.tosorted: 1.1.4
doctrine: 2.1.0 doctrine: 2.1.0
es-iterator-helpers: 1.2.1 es-iterator-helpers: 1.2.2
eslint: 9.39.1(jiti@2.6.1) eslint: 9.39.2(jiti@2.6.1)
estraverse: 5.3.0 estraverse: 5.3.0
hasown: 2.0.2 hasown: 2.0.2
jsx-ast-utils: 3.3.5 jsx-ast-utils: 3.3.5
@ -4690,15 +4690,15 @@ snapshots:
eslint-visitor-keys@4.2.1: {} eslint-visitor-keys@4.2.1: {}
eslint@9.39.1(jiti@2.6.1): eslint@9.39.2(jiti@2.6.1):
dependencies: dependencies:
'@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1))
'@eslint-community/regexpp': 4.12.2 '@eslint-community/regexpp': 4.12.2
'@eslint/config-array': 0.21.1 '@eslint/config-array': 0.21.1
'@eslint/config-helpers': 0.4.2 '@eslint/config-helpers': 0.4.2
'@eslint/core': 0.17.0 '@eslint/core': 0.17.0
'@eslint/eslintrc': 3.3.3 '@eslint/eslintrc': 3.3.3
'@eslint/js': 9.39.1 '@eslint/js': 9.39.2
'@eslint/plugin-kit': 0.4.1 '@eslint/plugin-kit': 0.4.1
'@humanfs/node': 0.16.7 '@humanfs/node': 0.16.7
'@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/module-importer': 1.0.1
@ -5652,7 +5652,7 @@ snapshots:
dependencies: dependencies:
'@next/env': 16.0.10 '@next/env': 16.0.10
'@swc/helpers': 0.5.15 '@swc/helpers': 0.5.15
caniuse-lite: 1.0.30001760 caniuse-lite: 1.0.30001761
postcss: 8.4.31 postcss: 8.4.31
react: 19.2.0 react: 19.2.0
react-dom: 19.2.0(react@19.2.0) react-dom: 19.2.0(react@19.2.0)
@ -5700,14 +5700,14 @@ snapshots:
dependencies: dependencies:
call-bind: 1.0.8 call-bind: 1.0.8
define-properties: 1.2.1 define-properties: 1.2.1
es-abstract: 1.24.0 es-abstract: 1.24.1
es-object-atoms: 1.1.1 es-object-atoms: 1.1.1
object.groupby@1.0.3: object.groupby@1.0.3:
dependencies: dependencies:
call-bind: 1.0.8 call-bind: 1.0.8
define-properties: 1.2.1 define-properties: 1.2.1
es-abstract: 1.24.0 es-abstract: 1.24.1
object.values@1.2.1: object.values@1.2.1:
dependencies: dependencies:
@ -5799,7 +5799,7 @@ snapshots:
queue-microtask@1.2.3: {} queue-microtask@1.2.3: {}
react-day-picker@9.12.0(react@19.2.0): react-day-picker@9.13.0(react@19.2.0):
dependencies: dependencies:
'@date-fns/tz': 1.4.1 '@date-fns/tz': 1.4.1
date-fns: 4.1.0 date-fns: 4.1.0
@ -5873,12 +5873,12 @@ snapshots:
react@19.2.0: {} react@19.2.0: {}
recharts@3.5.1(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react-is@16.13.1)(react@19.2.0)(redux@5.0.1): recharts@3.6.0(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react-is@16.13.1)(react@19.2.0)(redux@5.0.1):
dependencies: dependencies:
'@reduxjs/toolkit': 2.11.1(react-redux@9.2.0(@types/react@19.2.7)(react@19.2.0)(redux@5.0.1))(react@19.2.0) '@reduxjs/toolkit': 2.11.2(react-redux@9.2.0(@types/react@19.2.7)(react@19.2.0)(redux@5.0.1))(react@19.2.0)
clsx: 2.1.1 clsx: 2.1.1
decimal.js-light: 2.5.1 decimal.js-light: 2.5.1
es-toolkit: 1.42.0 es-toolkit: 1.43.0
eventemitter3: 5.0.1 eventemitter3: 5.0.1
immer: 10.2.0 immer: 10.2.0
react: 19.2.0 react: 19.2.0
@ -5903,7 +5903,7 @@ snapshots:
dependencies: dependencies:
call-bind: 1.0.8 call-bind: 1.0.8
define-properties: 1.2.1 define-properties: 1.2.1
es-abstract: 1.24.0 es-abstract: 1.24.1
es-errors: 1.3.0 es-errors: 1.3.0
es-object-atoms: 1.1.1 es-object-atoms: 1.1.1
get-intrinsic: 1.3.0 get-intrinsic: 1.3.0
@ -6111,14 +6111,14 @@ snapshots:
dependencies: dependencies:
call-bind: 1.0.8 call-bind: 1.0.8
define-properties: 1.2.1 define-properties: 1.2.1
es-abstract: 1.24.0 es-abstract: 1.24.1
string.prototype.matchall@4.0.12: string.prototype.matchall@4.0.12:
dependencies: dependencies:
call-bind: 1.0.8 call-bind: 1.0.8
call-bound: 1.0.4 call-bound: 1.0.4
define-properties: 1.2.1 define-properties: 1.2.1
es-abstract: 1.24.0 es-abstract: 1.24.1
es-errors: 1.3.0 es-errors: 1.3.0
es-object-atoms: 1.1.1 es-object-atoms: 1.1.1
get-intrinsic: 1.3.0 get-intrinsic: 1.3.0
@ -6132,7 +6132,7 @@ snapshots:
string.prototype.repeat@1.0.0: string.prototype.repeat@1.0.0:
dependencies: dependencies:
define-properties: 1.2.1 define-properties: 1.2.1
es-abstract: 1.24.0 es-abstract: 1.24.1
string.prototype.trim@1.2.10: string.prototype.trim@1.2.10:
dependencies: dependencies:
@ -6140,7 +6140,7 @@ snapshots:
call-bound: 1.0.4 call-bound: 1.0.4
define-data-property: 1.1.4 define-data-property: 1.1.4
define-properties: 1.2.1 define-properties: 1.2.1
es-abstract: 1.24.0 es-abstract: 1.24.1
es-object-atoms: 1.1.1 es-object-atoms: 1.1.1
has-property-descriptors: 1.0.2 has-property-descriptors: 1.0.2
@ -6260,13 +6260,13 @@ snapshots:
possible-typed-array-names: 1.1.0 possible-typed-array-names: 1.1.0
reflect.getprototypeof: 1.0.10 reflect.getprototypeof: 1.0.10
typescript-eslint@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): typescript-eslint@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3):
dependencies: dependencies:
'@typescript-eslint/eslint-plugin': 8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/eslint-plugin': 8.50.0(@typescript-eslint/parser@8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
'@typescript-eslint/parser': 8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
'@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3) '@typescript-eslint/typescript-estree': 8.50.0(typescript@5.9.3)
'@typescript-eslint/utils': 8.49.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/utils': 8.50.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)
eslint: 9.39.1(jiti@2.6.1) eslint: 9.39.2(jiti@2.6.1)
typescript: 5.9.3 typescript: 5.9.3
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@ -6339,7 +6339,7 @@ snapshots:
'@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1
'@unrs/resolver-binding-win32-x64-msvc': 1.11.1 '@unrs/resolver-binding-win32-x64-msvc': 1.11.1
update-browserslist-db@1.2.2(browserslist@4.28.1): update-browserslist-db@1.2.3(browserslist@4.28.1):
dependencies: dependencies:
browserslist: 4.28.1 browserslist: 4.28.1
escalade: 3.2.0 escalade: 3.2.0

View File

@ -10,6 +10,7 @@ stockstats
eodhd eodhd
langgraph langgraph
chromadb chromadb
sentence-transformers
setuptools setuptools
backtrader backtrader
akshare akshare

View File

@ -1,12 +1,59 @@
import os import os
import chromadb import chromadb
from chromadb.config import Settings from chromadb.config import Settings
from openai import OpenAI
class FinancialSituationMemory: class FinancialSituationMemory:
def __init__(self, name, config): def __init__(self, name, config):
self.embedding = "text-embedding-3-small" """
Initialize the memory with configurable embedding provider.
Config options:
embedding_provider: "local" (default) or "openai"
embedding_model: Model name for the embedding provider
- For local: "all-MiniLM-L6-v2" (default), "all-mpnet-base-v2", etc.
- For OpenAI: "text-embedding-3-small" (default), "text-embedding-3-large", etc.
embedding_base_url: Base URL for OpenAI-compatible API (only used when provider is "openai")
embedding_api_key: API key for OpenAI (only used when provider is "openai")
"""
self.provider = config.get("embedding_provider", "local").lower()
if self.provider == "local":
self._init_local_embedding(config)
elif self.provider == "openai":
self._init_openai_embedding(config)
else:
raise ValueError(f"Unsupported embedding provider: {self.provider}. Use 'local' or 'openai'.")
self.chroma_client = chromadb.Client(Settings(allow_reset=True))
self.situation_collection = self.chroma_client.get_or_create_collection(name=name)
def _init_local_embedding(self, config):
"""Initialize local embedding using sentence-transformers."""
try:
from sentence_transformers import SentenceTransformer
except ImportError:
raise ImportError(
"sentence-transformers is required for local embeddings. "
"Install it with: pip install sentence-transformers"
)
# Default to all-MiniLM-L6-v2 - a lightweight and efficient model
model_name = config.get("embedding_model", "all-MiniLM-L6-v2")
import logging
logging.info(f"Loading local embedding model: {model_name}")
self.model = SentenceTransformer(model_name)
self.embedding_dim = self.model.get_sentence_embedding_dimension()
logging.info(f"Local embedding model loaded. Dimension: {self.embedding_dim}")
def _init_openai_embedding(self, config):
"""Initialize OpenAI embedding client."""
from openai import OpenAI
self.embedding_model = config.get("embedding_model", "text-embedding-3-small")
# Get embedding configuration from config, with fallbacks # Get embedding configuration from config, with fallbacks
embedding_base_url = config.get("embedding_base_url", "https://api.openai.com/v1") embedding_base_url = config.get("embedding_base_url", "https://api.openai.com/v1")
@ -23,23 +70,37 @@ class FinancialSituationMemory:
import logging import logging
logging.warning("Using LLM API key for embeddings. Consider setting embedding_api_key or OPENAI_API_KEY.") logging.warning("Using LLM API key for embeddings. Consider setting embedding_api_key or OPENAI_API_KEY.")
if not embedding_api_key:
raise ValueError(
"OpenAI API key is required for OpenAI embeddings. "
"Set 'embedding_api_key' in config or OPENAI_API_KEY environment variable, "
"or use 'embedding_provider': 'local' for local embeddings without API key."
)
# Use configured endpoint for embeddings # Use configured endpoint for embeddings
self.client = OpenAI(base_url=embedding_base_url, api_key=embedding_api_key) self.client = OpenAI(base_url=embedding_base_url, api_key=embedding_api_key)
self.chroma_client = chromadb.Client(Settings(allow_reset=True))
self.situation_collection = self.chroma_client.get_or_create_collection(name=name)
def get_embedding(self, text): def get_embedding(self, text):
"""Get OpenAI embedding for a text""" """Get embedding for a text using the configured provider."""
# Truncate text to avoid exceeding embedding model's token limit # Truncate text to avoid exceeding embedding model's token limit
# text-embedding-3-small has 8192 token limit
# For mixed Chinese/English text, estimate ~1.5-2 tokens per character
# Target: ~4000 characters to stay well under 8192 tokens
max_chars = 4000 max_chars = 4000
if len(text) > max_chars: if len(text) > max_chars:
text = text[:max_chars] text = text[:max_chars]
if self.provider == "local":
return self._get_local_embedding(text)
else:
return self._get_openai_embedding(text)
def _get_local_embedding(self, text):
"""Get embedding using local sentence-transformers model."""
embedding = self.model.encode(text, normalize_embeddings=True)
return embedding.tolist()
def _get_openai_embedding(self, text):
"""Get embedding using OpenAI API."""
response = self.client.embeddings.create( response = self.client.embeddings.create(
model=self.embedding, input=text model=self.embedding_model, input=text
) )
return response.data[0].embedding return response.data[0].embedding
@ -67,7 +128,7 @@ class FinancialSituationMemory:
) )
def get_memories(self, current_situation, n_matches=1): def get_memories(self, current_situation, n_matches=1):
"""Find matching recommendations using OpenAI embeddings""" """Find matching recommendations using embeddings"""
query_embedding = self.get_embedding(current_situation) query_embedding = self.get_embedding(current_situation)
results = self.situation_collection.query( results = self.situation_collection.query(
@ -90,8 +151,13 @@ class FinancialSituationMemory:
if __name__ == "__main__": if __name__ == "__main__":
# Example usage # Example usage with local embedding (no API key required!)
matcher = FinancialSituationMemory() config = {
"embedding_provider": "local", # Use local model, no API key needed
"embedding_model": "all-MiniLM-L6-v2", # Lightweight and efficient
}
matcher = FinancialSituationMemory("test_memory", config)
# Example data # Example data
example_data = [ example_data = [
@ -114,7 +180,9 @@ if __name__ == "__main__":
] ]
# Add the example situations and recommendations # Add the example situations and recommendations
print("Adding example situations...")
matcher.add_situations(example_data) matcher.add_situations(example_data)
print("Done!")
# Example query # Example query
current_situation = """ current_situation = """
@ -123,6 +191,7 @@ if __name__ == "__main__":
""" """
try: try:
print("\nSearching for recommendations...")
recommendations = matcher.get_memories(current_situation, n_matches=2) recommendations = matcher.get_memories(current_situation, n_matches=2)
for i, rec in enumerate(recommendations, 1): for i, rec in enumerate(recommendations, 1):