Rajeev Ranjan Pandey commited on
Commit
e078b1d
·
0 Parent(s):

Refine UI and fix model selection bugs

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitignore +28 -0
  2. Dockerfile.backend +6 -0
  3. Dockerfile.frontend +6 -0
  4. Makefile +19 -0
  5. README.md +72 -0
  6. backend/dependencies.py +4 -0
  7. backend/main.py +132 -0
  8. backend/model_cache.py +9 -0
  9. backend/routers/compare.py +2 -0
  10. backend/routers/health.py +4 -0
  11. backend/routers/summarize.py +2 -0
  12. config.yaml +91 -0
  13. data/interim/.gitkeep +0 -0
  14. data/processed/.gitkeep +0 -0
  15. data/raw/.gitkeep +0 -0
  16. docker-compose.yml +19 -0
  17. docs/architecture.md +6 -0
  18. docs/paper/main.tex +17 -0
  19. docs/paper/references.bib +27 -0
  20. docs/poster/poster_content.md +16 -0
  21. docs/presentation/outline.md +7 -0
  22. frontend/index.html +1 -0
  23. frontend/package-lock.json +2881 -0
  24. frontend/package.json +24 -0
  25. frontend/postcss.config.js +1 -0
  26. frontend/src/App.jsx +2 -0
  27. frontend/src/api/client.js +20 -0
  28. frontend/src/components/BatchUpload.jsx +21 -0
  29. frontend/src/components/CompareGrid.jsx +25 -0
  30. frontend/src/components/DatasetToggle.jsx +45 -0
  31. frontend/src/components/LengthSlider.jsx +25 -0
  32. frontend/src/components/ModelSelector.jsx +31 -0
  33. frontend/src/components/SampleGallery.jsx +42 -0
  34. frontend/src/components/SummarizerWidget.jsx +310 -0
  35. frontend/src/components/SummaryCard.jsx +56 -0
  36. frontend/src/components/TextInputPanel.jsx +20 -0
  37. frontend/src/index.css +27 -0
  38. frontend/src/main.jsx +5 -0
  39. frontend/src/pages/Home.jsx +150 -0
  40. frontend/tailwind.config.js +2 -0
  41. frontend/vite.config.js +3 -0
  42. notebooks/01_data_exploration.ipynb +34 -0
  43. notebooks/02_model_evaluation.ipynb +52 -0
  44. notebooks/03_results_for_paper.ipynb +34 -0
  45. pyproject.toml +14 -0
  46. requirements.txt +23 -0
  47. scripts/download_notes.md +19 -0
  48. scripts/export_results.sh +3 -0
  49. scripts/run_local_backend.sh +3 -0
  50. scripts/run_local_frontend.sh +4 -0
.gitignore ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ venv/
5
+ .env
6
+ .env.*
7
+ *.env
8
+ kaggle.json
9
+ ~/.kaggle/
10
+ .ipynb_checkpoints/
11
+ .pytest_cache/
12
+ node_modules/
13
+ frontend/dist/
14
+ data/raw/*
15
+ !data/raw/.gitkeep
16
+ data/raw/gcc/*.csv
17
+ !data/raw/gcc/source_manifest.csv
18
+ data/interim/*
19
+ !data/interim/.gitkeep
20
+ data/processed/*
21
+ !data/processed/.gitkeep
22
+ # Large model weights
23
+ *.h5
24
+ *.bin
25
+ *.pt
26
+ *.ckpt
27
+ *.gguf
28
+ *.safetensors
Dockerfile.backend ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+ WORKDIR /app
3
+ COPY requirements.txt .
4
+ RUN pip install --no-cache-dir -r requirements.txt
5
+ COPY . .
6
+ EXPOSE 8000
Dockerfile.frontend ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ FROM node:20-alpine
2
+ WORKDIR /app
3
+ COPY frontend/package*.json ./
4
+ RUN npm install
5
+ COPY frontend/ .
6
+ EXPOSE 5173
Makefile ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ PYTHON=python
2
+
3
+ prepare:
4
+ $(PYTHON) -m src.cli.run_prepare --input data/raw/US_Accidents_March23.csv
5
+
6
+ sample-eval:
7
+ $(PYTHON) -m src.data.sample_eval_set --input data/interim/eval_candidates.csv --output data/processed/eval_set_with_refs.csv --n 150
8
+
9
+ infer:
10
+ $(PYTHON) -m src.cli.run_inference --input data/processed/eval_set_with_refs.csv --output data/processed/model_outputs.csv --models lead1 textrank flan_t5_small bart_large_cnn
11
+
12
+ eval:
13
+ $(PYTHON) -m src.cli.run_evaluation --input data/processed/model_outputs.csv --output data/processed/aggregate_metrics.csv
14
+
15
+ backend:
16
+ uvicorn backend.main:app --reload --port 8000
17
+
18
+ frontend:
19
+ cd frontend && npm install && npm run dev
README.md ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # CUD - AAI - Midterm Project - Traffic Incident Summarization
2
+
3
+ This repo compares extractive and abstractive summarization methods for traffic incident reports and ships with a polished React + FastAPI demo.
4
+
5
+ ## What is included
6
+
7
+ - U.S. Accidents ingestion with automatic Kaggle download support
8
+ - GCC regional track with bundled Dubai, Abu Dhabi, and UAE federal sample datasets
9
+ - Rule-based GCC narrative generation so structured GCC records become natural-language incident reports
10
+ - Baselines: Lead-1 and TextRank
11
+ - Abstractive models: BART, Flan-T5, optional PEGASUS
12
+ - Evaluation pipeline, notebooks, LaTeX paper draft, poster content, and a demo UI
13
+
14
+ ## GCC data note
15
+
16
+ The repo now includes **official source references** for Dubai Pulse, Abu Dhabi Open Data, and UAE federal traffic statistics, along with **normalized bundled sample files** so the project runs immediately offline. This is the practical compromise because public GCC portals often expose structured records, JavaScript-only dashboards, or gated exports rather than ready-to-bundle narrative text.
17
+
18
+ In the paper, describe the GCC track like this:
19
+
20
+ > Structured GCC traffic records were normalized into a common schema and converted into operator-style narrative incident descriptions using a rule-based text generator. Official source references were retained for provenance, while bundled sample extracts were used to make the demo reproducible offline.
21
+
22
+ ## Quick start
23
+
24
+ ### 1. Python environment
25
+
26
+ ```bash
27
+ python -m venv .venv
28
+ source .venv/bin/activate
29
+ pip install -r requirements.txt
30
+ ```
31
+
32
+ ### 2. Prepare data
33
+
34
+ ```bash
35
+ python -m src.cli.run_prepare --source both
36
+ ```
37
+
38
+ Behavior:
39
+
40
+ - If `data/raw/US_Accidents_March23.csv` is missing, the script attempts Kaggle download.
41
+ - GCC sample sources are already bundled.
42
+ - A combined corpus is written to `data/interim/combined_incident_corpus.csv`.
43
+
44
+ ### 3. Start backend
45
+
46
+ ```bash
47
+ uvicorn backend.main:app --reload --port 8000
48
+ ```
49
+
50
+ ### 4. Start frontend
51
+
52
+ ```bash
53
+ cd frontend
54
+ npm install
55
+ npm run dev
56
+ ```
57
+
58
+ ## Demo features
59
+
60
+ - Beautiful hero dashboard for screenshots
61
+ - Dataset track toggle: US or GCC
62
+ - Sample incident picker
63
+ - Summarize and compare endpoints
64
+ - Copy and download summary cards
65
+ - Batch CSV upload preview
66
+
67
+ ## Important paths
68
+
69
+ - `data/raw/gcc/source_manifest.csv`
70
+ - `data/interim/gcc_narratives.csv`
71
+ - `docs/paper/main.tex`
72
+ - `docs/poster/poster_content.md`
backend/dependencies.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ from functools import lru_cache
2
+ @lru_cache(maxsize=1)
3
+ def app_metadata():
4
+ return {"name": "Traffic Incident Summarization API", "version": "0.1.0"}
backend/main.py ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ import pandas as pd
6
+ from fastapi import FastAPI, HTTPException
7
+ from fastapi.middleware.cors import CORSMiddleware
8
+
9
+ from src.app.schemas import (
10
+ CompareRequest,
11
+ CompareResponse,
12
+ CompareResponseItem,
13
+ SampleItem,
14
+ SamplesResponse,
15
+ SummarizeRequest,
16
+ SummarizeResponse,
17
+ )
18
+ from src.app.services import summarize_with_model
19
+ from src.data.prepare import prepare_dataset
20
+ from src.data.utils import load_config
21
+
22
+ app = FastAPI(title="Traffic Incident Summarization API", version="0.4.0")
23
+ app.add_middleware(
24
+ CORSMiddleware,
25
+ allow_origins=["http://localhost:5173", "http://127.0.0.1:5173"],
26
+ allow_credentials=True,
27
+ allow_methods=["*"],
28
+ allow_headers=["*"],
29
+ )
30
+
31
+
32
+ @app.on_event("startup")
33
+ def startup_prepare() -> None:
34
+ cfg = load_config()
35
+ combined = Path(cfg["paths"]["combined_corpus_csv"])
36
+ if not combined.exists():
37
+ try:
38
+ prepare_dataset(source="gcc", config_path="config.yaml")
39
+ except Exception:
40
+ # keep startup resilient, especially when Kaggle credentials are absent
41
+ pass
42
+
43
+
44
+ @app.get("/health")
45
+ def health():
46
+ return {"status": "ok", "service": "traffic-incident-summarization", "version": "0.4.0"}
47
+
48
+
49
+ @app.get("/samples", response_model=SamplesResponse)
50
+ def get_samples(track: str = "gcc"):
51
+ cfg = load_config()
52
+ combined_path = Path(cfg["paths"]["combined_corpus_csv"])
53
+ if not combined_path.exists():
54
+ prepare_dataset(source="gcc", config_path="config.yaml")
55
+ df = pd.read_csv(combined_path)
56
+ if "dataset_track" in df.columns:
57
+ df = df[df["dataset_track"].fillna("us") == track]
58
+ if df.empty:
59
+ raise HTTPException(status_code=404, detail=f"No samples found for dataset track: {track}")
60
+
61
+ if "Start_Time" in df.columns:
62
+ df["Start_Time"] = pd.to_datetime(df["Start_Time"], errors="coerce")
63
+ df = df.sort_values(by="Start_Time", ascending=False)
64
+
65
+ sample_df = df.head(10).copy()
66
+ items = []
67
+ for idx, row in sample_df.iterrows():
68
+ def clean(val):
69
+ s = str(val).strip() if pd.notna(val) else ""
70
+ return "" if s.lower() in ("nan", "none", "") else s
71
+
72
+ loc_cols = ["road_name", "Street", "district", "City", "State", "emirate"]
73
+ location_parts = [clean(row.get(col)) for col in loc_cols]
74
+ title = " · ".join([p for p in location_parts if p][:3]) or f"Sample incident {idx + 1}"
75
+
76
+ desc = clean(row.get("Description", "")) or "No description available."
77
+
78
+ sev = row.get("Severity", "")
79
+ if clean(str(sev)):
80
+ if "severity" not in desc.lower():
81
+ try:
82
+ sev_int = int(float(sev))
83
+ sev_map = {1: "Low", 2: "Medium", 3: "High", 4: "Critical"}
84
+ sev_str = sev_map.get(sev_int, "Medium")
85
+ desc = f"{desc} Classified as {sev_str} severity."
86
+ except Exception:
87
+ pass
88
+
89
+ src_lbl = clean(row.get("source_label", ""))
90
+ if not src_lbl:
91
+ src_lbl = "US Accidents" if track == "us" else "GCC sample"
92
+
93
+ items.append(
94
+ SampleItem(
95
+ id=str(idx + 1),
96
+ dataset_track=track,
97
+ title=title,
98
+ text=desc,
99
+ source_label=src_lbl,
100
+ )
101
+ )
102
+ return SamplesResponse(items=items)
103
+
104
+
105
+ @app.post("/summarize", response_model=SummarizeResponse)
106
+ def summarize(request: SummarizeRequest):
107
+ try:
108
+ summary = summarize_with_model(request.text, request.model_choice, request.max_length)
109
+ return SummarizeResponse(
110
+ model_name=request.model_choice,
111
+ summary=summary,
112
+ dataset_track=request.dataset_track,
113
+ word_count=len(summary.split()),
114
+ )
115
+ except Exception as exc:
116
+ raise HTTPException(status_code=500, detail=str(exc)) from exc
117
+
118
+
119
+ @app.post("/compare", response_model=CompareResponse)
120
+ def compare(request: CompareRequest):
121
+ try:
122
+ items = [
123
+ CompareResponseItem(
124
+ model_name=m,
125
+ summary=summarize_with_model(request.text, m, request.max_length),
126
+ word_count=len(summarize_with_model(request.text, m, request.max_length).split()),
127
+ )
128
+ for m in request.model_choices
129
+ ]
130
+ return CompareResponse(dataset_track=request.dataset_track, items=items)
131
+ except Exception as exc:
132
+ raise HTTPException(status_code=500, detail=str(exc)) from exc
backend/model_cache.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ from src.models.abstractive import available_abstractive_models, build_generation_config, load_tokenizer_and_model
2
+ from functools import lru_cache
3
+ @lru_cache(maxsize=8)
4
+ def warm_model(model_name: str):
5
+ if model_name in available_abstractive_models() or model_name == "pegasus_cnn":
6
+ hf_name, _ = build_generation_config(model_name)
7
+ load_tokenizer_and_model(hf_name)
8
+ return hf_name
9
+ return model_name
backend/routers/compare.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ from fastapi import APIRouter
2
+ router=APIRouter()
backend/routers/health.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ from fastapi import APIRouter
2
+ router=APIRouter()
3
+ @router.get("/health")
4
+ def health(): return {"status":"ok"}
backend/routers/summarize.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ from fastapi import APIRouter
2
+ router=APIRouter()
config.yaml ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project:
2
+ name: "traffic-incident-summarization"
3
+ random_seed: 42
4
+
5
+ paths:
6
+ raw_csv: "data/raw/US_Accidents_March23.csv"
7
+ cleaned_csv: "data/interim/cleaned_incidents.csv"
8
+ experiment_sample_csv: "data/interim/experiment_sample.csv"
9
+ eval_candidates_csv: "data/interim/eval_candidates.csv"
10
+ eval_set_csv: "data/processed/eval_set_with_refs.csv"
11
+ model_outputs_csv: "data/processed/model_outputs.csv"
12
+ aggregate_metrics_csv: "data/processed/aggregate_metrics.csv"
13
+ gcc_dir: "data/raw/gcc"
14
+ gcc_manifest_csv: "data/raw/gcc/source_manifest.csv"
15
+ gcc_combined_structured_csv: "data/interim/gcc_structured_combined.csv"
16
+ gcc_narratives_csv: "data/interim/gcc_narratives.csv"
17
+ combined_corpus_csv: "data/interim/combined_incident_corpus.csv"
18
+
19
+ dataset:
20
+ kaggle_handle: "sobhanmoosavi/us-accidents"
21
+ expected_filename: "US_Accidents_March23.csv"
22
+ auto_download: true
23
+
24
+ gcc:
25
+ enabled: true
26
+ include_in_combined_corpus: true
27
+ narrative_rows_per_source: 250
28
+ default_country: "United Arab Emirates"
29
+ source_priority:
30
+ - "dubai_pulse_incidents"
31
+ - "uae_federal_traffic_stats"
32
+ - "abu_dhabi_open_data"
33
+ sources:
34
+ dubai_pulse_incidents:
35
+ label: "Dubai Pulse Traffic Incidents"
36
+ official_url: "https://www.dubaipulse.gov.ae/data/dp-traffic/dp_traffic_incidents-open"
37
+ access_type: "open-data-portal"
38
+ local_sample_csv: "data/raw/gcc/dubai_pulse_incidents_sample.csv"
39
+ status: "bundled_sample"
40
+ notes: "Real-time Dubai Police incident feed surfaced through Dubai Pulse. The bundled CSV is a normalized local sample schema for immediate demo use."
41
+ uae_federal_traffic_stats:
42
+ label: "UAE Federal Traffic Statistics"
43
+ official_url: "https://uaestat.fcsc.gov.ae/vis?df%5Bag%5D=FCSA&df%5Bds%5D=FCSC-RDS&df%5Bid%5D=DF_TRA_TYPE&df%5Bvs%5D=3.0.0"
44
+ access_type: "web-statistics-portal"
45
+ local_sample_csv: "data/raw/gcc/uae_federal_traffic_stats_sample.csv"
46
+ status: "bundled_sample"
47
+ notes: "Federal accident indicators by emirate and accident type. The bundled CSV is a narrative-ready extracted sample schema."
48
+ abu_dhabi_open_data:
49
+ label: "Abu Dhabi Open Data"
50
+ official_url: "https://data.abudhabi/opendata/dataset"
51
+ access_type: "open-data-catalog"
52
+ local_sample_csv: "data/raw/gcc/abu_dhabi_incidents_sample.csv"
53
+ status: "bundled_sample"
54
+ notes: "Abu Dhabi open data catalog entry point. The bundled CSV is a normalized road incident sample for regional coverage."
55
+
56
+ data:
57
+ text_column: "Description"
58
+ min_chars: 50
59
+ max_chars: 1500
60
+ experiment_sample_size: 3000
61
+ eval_candidate_size: 300
62
+ gcc_eval_candidate_size: 120
63
+ deduplicate: true
64
+ stratify_by:
65
+ - "Severity"
66
+
67
+ generation:
68
+ default_max_input_tokens: 512
69
+ default_max_new_tokens: 96
70
+ default_min_new_tokens: 20
71
+ num_beams: 4
72
+ length_penalty: 1.0
73
+ no_repeat_ngram_size: 3
74
+ early_stopping: true
75
+
76
+ models:
77
+ bart_large_cnn:
78
+ hf_name: "facebook/bart-large-cnn"
79
+ enabled: true
80
+ prompt_prefix: ""
81
+ max_input_tokens: 512
82
+ flan_t5_small:
83
+ hf_name: "google/flan-t5-small"
84
+ enabled: true
85
+ prompt_prefix: "summarize: "
86
+ max_input_tokens: 512
87
+ pegasus_cnn:
88
+ hf_name: "google/pegasus-cnn_dailymail"
89
+ enabled: false
90
+ prompt_prefix: ""
91
+ max_input_tokens: 512
data/interim/.gitkeep ADDED
File without changes
data/processed/.gitkeep ADDED
File without changes
data/raw/.gitkeep ADDED
File without changes
docker-compose.yml ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: "3.9"
2
+ services:
3
+ backend:
4
+ build:
5
+ context: .
6
+ dockerfile: Dockerfile.backend
7
+ command: uvicorn backend.main:app --host 0.0.0.0 --port 8000
8
+ ports: ["8000:8000"]
9
+ volumes: ["./:/app"]
10
+ working_dir: /app
11
+ frontend:
12
+ build:
13
+ context: .
14
+ dockerfile: Dockerfile.frontend
15
+ command: npm run dev -- --host 0.0.0.0
16
+ ports: ["5173:5173"]
17
+ volumes: ["./frontend:/app"]
18
+ working_dir: /app
19
+ depends_on: [backend]
docs/architecture.md ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ # GCC V4 architecture update
2
+
3
+ - US track uses Kaggle U.S. Accidents data.
4
+ - GCC track uses official source references plus bundled normalized sample extracts.
5
+ - A rule-based generator transforms structured GCC records into narrative incident descriptions.
6
+ - The same summarization layer powers notebooks, CLI runs, FastAPI endpoints, and the React demo.
docs/paper/main.tex ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ \documentclass[conference]{IEEEtran}
2
+ \usepackage{graphicx}
3
+ \usepackage{booktabs}
4
+ \usepackage{url}
5
+ \begin{document}
6
+ \title{Transformer-Based Abstractive Summarization for Traffic Incident Reports: Comparative Evaluation of BART, Flan-T5, PEGASUS, and Extractive Baselines}
7
+ \author{Rajeev Ranjan Pandey}
8
+ \maketitle
9
+ \begin{abstract}
10
+ This project evaluates extractive and abstractive summarization methods for traffic incident reports using a large U.S. narrative corpus and a GCC regional track derived from structured traffic records tied to Dubai Pulse, Abu Dhabi open data, and UAE federal road-safety statistics. The GCC records are normalized into a common schema and transformed into operator-style narrative descriptions to enable summarization experiments in a regional smart-mobility context.\end{abstract}
11
+ \section{Dataset Note}
12
+ The U.S. Accidents dataset provides large-scale narrative descriptions. GCC public sources more often provide structured records, portal-based feeds, or JavaScript dashboards rather than directly downloadable narrative incident text. To preserve reproducibility, this project bundles normalized sample extracts aligned to official source references and converts those records into narrative incident descriptions through a rule-based generator.
13
+ \section{Demo Note}
14
+ The React frontend includes a GCC-aware dataset toggle and polished output cards for poster-quality screenshots.
15
+ \bibliographystyle{IEEEtran}
16
+ \bibliography{references}
17
+ \end{document}
docs/paper/references.bib ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @article{moosavi2019usaccidents,
2
+ title={A Countrywide Traffic Accident Dataset},
3
+ author={Moosavi, Sobhan and others},
4
+ journal={arXiv preprint arXiv:1906.05409},
5
+ year={2019}
6
+ }
7
+
8
+ @article{lewis2020bart,
9
+ title={BART: Denoising Sequence-to-Sequence Pre-training for Natural Language Generation, Translation, and Comprehension},
10
+ author={Lewis, Mike and others},
11
+ journal={ACL},
12
+ year={2020}
13
+ }
14
+
15
+ @article{raffel2020t5,
16
+ title={Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer},
17
+ author={Raffel, Colin and others},
18
+ journal={JMLR},
19
+ year={2020}
20
+ }
21
+
22
+ @article{zhang2020pegasus,
23
+ title={PEGASUS: Pre-training with Extracted Gap-sentences for Abstractive Summarization},
24
+ author={Zhang, Jingqing and others},
25
+ journal={ICML},
26
+ year={2020}
27
+ }
docs/poster/poster_content.md ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Poster content, GCC V4
2
+
3
+ ## Title
4
+ Transformer-Based Abstractive Summarization for Traffic Incident Reports
5
+
6
+ ## Regional angle
7
+ - Includes a GCC track centered on Dubai, Abu Dhabi, and UAE federal sources
8
+ - Structured regional traffic records converted into operator-style incident descriptions
9
+ - Demo supports direct US vs GCC comparison
10
+
11
+ ## Visuals
12
+ 1. Model comparison bar chart
13
+ 2. GCC source manifest table
14
+ 3. Example GCC structured record to narrative conversion
15
+ 4. Side-by-side summaries in the React UI
16
+ 5. Demo QR linking to the local or hosted app screenshot
docs/presentation/outline.md ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ 1. Problem
2
+ 2. Dataset
3
+ 3. Models
4
+ 4. Evaluation
5
+ 5. Results
6
+ 6. Demo
7
+ 7. Future work
frontend/index.html ADDED
@@ -0,0 +1 @@
 
 
1
+ <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Traffic Incident Summarizer</title></head><body class="bg-slate-100"><div id="root"></div><script type="module" src="/src/main.jsx"></script></body></html>
frontend/package-lock.json ADDED
@@ -0,0 +1,2881 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "traffic-incident-summarization-frontend",
3
+ "version": "0.1.0",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "traffic-incident-summarization-frontend",
9
+ "version": "0.1.0",
10
+ "dependencies": {
11
+ "axios": "^1.7.2",
12
+ "lucide-react": "^0.395.0",
13
+ "react": "^18.3.1",
14
+ "react-dom": "^18.3.1"
15
+ },
16
+ "devDependencies": {
17
+ "@vitejs/plugin-react": "^4.3.1",
18
+ "autoprefixer": "^10.4.19",
19
+ "postcss": "^8.4.38",
20
+ "tailwindcss": "^3.4.4",
21
+ "vite": "^5.2.12"
22
+ }
23
+ },
24
+ "node_modules/@alloc/quick-lru": {
25
+ "version": "5.2.0",
26
+ "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
27
+ "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
28
+ "dev": true,
29
+ "license": "MIT",
30
+ "engines": {
31
+ "node": ">=10"
32
+ },
33
+ "funding": {
34
+ "url": "https://github.com/sponsors/sindresorhus"
35
+ }
36
+ },
37
+ "node_modules/@babel/code-frame": {
38
+ "version": "7.29.0",
39
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
40
+ "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
41
+ "dev": true,
42
+ "license": "MIT",
43
+ "dependencies": {
44
+ "@babel/helper-validator-identifier": "^7.28.5",
45
+ "js-tokens": "^4.0.0",
46
+ "picocolors": "^1.1.1"
47
+ },
48
+ "engines": {
49
+ "node": ">=6.9.0"
50
+ }
51
+ },
52
+ "node_modules/@babel/compat-data": {
53
+ "version": "7.29.0",
54
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz",
55
+ "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==",
56
+ "dev": true,
57
+ "license": "MIT",
58
+ "engines": {
59
+ "node": ">=6.9.0"
60
+ }
61
+ },
62
+ "node_modules/@babel/core": {
63
+ "version": "7.29.0",
64
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
65
+ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
66
+ "dev": true,
67
+ "license": "MIT",
68
+ "dependencies": {
69
+ "@babel/code-frame": "^7.29.0",
70
+ "@babel/generator": "^7.29.0",
71
+ "@babel/helper-compilation-targets": "^7.28.6",
72
+ "@babel/helper-module-transforms": "^7.28.6",
73
+ "@babel/helpers": "^7.28.6",
74
+ "@babel/parser": "^7.29.0",
75
+ "@babel/template": "^7.28.6",
76
+ "@babel/traverse": "^7.29.0",
77
+ "@babel/types": "^7.29.0",
78
+ "@jridgewell/remapping": "^2.3.5",
79
+ "convert-source-map": "^2.0.0",
80
+ "debug": "^4.1.0",
81
+ "gensync": "^1.0.0-beta.2",
82
+ "json5": "^2.2.3",
83
+ "semver": "^6.3.1"
84
+ },
85
+ "engines": {
86
+ "node": ">=6.9.0"
87
+ },
88
+ "funding": {
89
+ "type": "opencollective",
90
+ "url": "https://opencollective.com/babel"
91
+ }
92
+ },
93
+ "node_modules/@babel/generator": {
94
+ "version": "7.29.1",
95
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
96
+ "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
97
+ "dev": true,
98
+ "license": "MIT",
99
+ "dependencies": {
100
+ "@babel/parser": "^7.29.0",
101
+ "@babel/types": "^7.29.0",
102
+ "@jridgewell/gen-mapping": "^0.3.12",
103
+ "@jridgewell/trace-mapping": "^0.3.28",
104
+ "jsesc": "^3.0.2"
105
+ },
106
+ "engines": {
107
+ "node": ">=6.9.0"
108
+ }
109
+ },
110
+ "node_modules/@babel/helper-compilation-targets": {
111
+ "version": "7.28.6",
112
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
113
+ "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
114
+ "dev": true,
115
+ "license": "MIT",
116
+ "dependencies": {
117
+ "@babel/compat-data": "^7.28.6",
118
+ "@babel/helper-validator-option": "^7.27.1",
119
+ "browserslist": "^4.24.0",
120
+ "lru-cache": "^5.1.1",
121
+ "semver": "^6.3.1"
122
+ },
123
+ "engines": {
124
+ "node": ">=6.9.0"
125
+ }
126
+ },
127
+ "node_modules/@babel/helper-globals": {
128
+ "version": "7.28.0",
129
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
130
+ "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
131
+ "dev": true,
132
+ "license": "MIT",
133
+ "engines": {
134
+ "node": ">=6.9.0"
135
+ }
136
+ },
137
+ "node_modules/@babel/helper-module-imports": {
138
+ "version": "7.28.6",
139
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
140
+ "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
141
+ "dev": true,
142
+ "license": "MIT",
143
+ "dependencies": {
144
+ "@babel/traverse": "^7.28.6",
145
+ "@babel/types": "^7.28.6"
146
+ },
147
+ "engines": {
148
+ "node": ">=6.9.0"
149
+ }
150
+ },
151
+ "node_modules/@babel/helper-module-transforms": {
152
+ "version": "7.28.6",
153
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
154
+ "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
155
+ "dev": true,
156
+ "license": "MIT",
157
+ "dependencies": {
158
+ "@babel/helper-module-imports": "^7.28.6",
159
+ "@babel/helper-validator-identifier": "^7.28.5",
160
+ "@babel/traverse": "^7.28.6"
161
+ },
162
+ "engines": {
163
+ "node": ">=6.9.0"
164
+ },
165
+ "peerDependencies": {
166
+ "@babel/core": "^7.0.0"
167
+ }
168
+ },
169
+ "node_modules/@babel/helper-plugin-utils": {
170
+ "version": "7.28.6",
171
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz",
172
+ "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==",
173
+ "dev": true,
174
+ "license": "MIT",
175
+ "engines": {
176
+ "node": ">=6.9.0"
177
+ }
178
+ },
179
+ "node_modules/@babel/helper-string-parser": {
180
+ "version": "7.27.1",
181
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
182
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
183
+ "dev": true,
184
+ "license": "MIT",
185
+ "engines": {
186
+ "node": ">=6.9.0"
187
+ }
188
+ },
189
+ "node_modules/@babel/helper-validator-identifier": {
190
+ "version": "7.28.5",
191
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
192
+ "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
193
+ "dev": true,
194
+ "license": "MIT",
195
+ "engines": {
196
+ "node": ">=6.9.0"
197
+ }
198
+ },
199
+ "node_modules/@babel/helper-validator-option": {
200
+ "version": "7.27.1",
201
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
202
+ "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
203
+ "dev": true,
204
+ "license": "MIT",
205
+ "engines": {
206
+ "node": ">=6.9.0"
207
+ }
208
+ },
209
+ "node_modules/@babel/helpers": {
210
+ "version": "7.28.6",
211
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz",
212
+ "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==",
213
+ "dev": true,
214
+ "license": "MIT",
215
+ "dependencies": {
216
+ "@babel/template": "^7.28.6",
217
+ "@babel/types": "^7.28.6"
218
+ },
219
+ "engines": {
220
+ "node": ">=6.9.0"
221
+ }
222
+ },
223
+ "node_modules/@babel/parser": {
224
+ "version": "7.29.0",
225
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz",
226
+ "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==",
227
+ "dev": true,
228
+ "license": "MIT",
229
+ "dependencies": {
230
+ "@babel/types": "^7.29.0"
231
+ },
232
+ "bin": {
233
+ "parser": "bin/babel-parser.js"
234
+ },
235
+ "engines": {
236
+ "node": ">=6.0.0"
237
+ }
238
+ },
239
+ "node_modules/@babel/plugin-transform-react-jsx-self": {
240
+ "version": "7.27.1",
241
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
242
+ "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
243
+ "dev": true,
244
+ "license": "MIT",
245
+ "dependencies": {
246
+ "@babel/helper-plugin-utils": "^7.27.1"
247
+ },
248
+ "engines": {
249
+ "node": ">=6.9.0"
250
+ },
251
+ "peerDependencies": {
252
+ "@babel/core": "^7.0.0-0"
253
+ }
254
+ },
255
+ "node_modules/@babel/plugin-transform-react-jsx-source": {
256
+ "version": "7.27.1",
257
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
258
+ "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
259
+ "dev": true,
260
+ "license": "MIT",
261
+ "dependencies": {
262
+ "@babel/helper-plugin-utils": "^7.27.1"
263
+ },
264
+ "engines": {
265
+ "node": ">=6.9.0"
266
+ },
267
+ "peerDependencies": {
268
+ "@babel/core": "^7.0.0-0"
269
+ }
270
+ },
271
+ "node_modules/@babel/template": {
272
+ "version": "7.28.6",
273
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
274
+ "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
275
+ "dev": true,
276
+ "license": "MIT",
277
+ "dependencies": {
278
+ "@babel/code-frame": "^7.28.6",
279
+ "@babel/parser": "^7.28.6",
280
+ "@babel/types": "^7.28.6"
281
+ },
282
+ "engines": {
283
+ "node": ">=6.9.0"
284
+ }
285
+ },
286
+ "node_modules/@babel/traverse": {
287
+ "version": "7.29.0",
288
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
289
+ "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
290
+ "dev": true,
291
+ "license": "MIT",
292
+ "dependencies": {
293
+ "@babel/code-frame": "^7.29.0",
294
+ "@babel/generator": "^7.29.0",
295
+ "@babel/helper-globals": "^7.28.0",
296
+ "@babel/parser": "^7.29.0",
297
+ "@babel/template": "^7.28.6",
298
+ "@babel/types": "^7.29.0",
299
+ "debug": "^4.3.1"
300
+ },
301
+ "engines": {
302
+ "node": ">=6.9.0"
303
+ }
304
+ },
305
+ "node_modules/@babel/types": {
306
+ "version": "7.29.0",
307
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
308
+ "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
309
+ "dev": true,
310
+ "license": "MIT",
311
+ "dependencies": {
312
+ "@babel/helper-string-parser": "^7.27.1",
313
+ "@babel/helper-validator-identifier": "^7.28.5"
314
+ },
315
+ "engines": {
316
+ "node": ">=6.9.0"
317
+ }
318
+ },
319
+ "node_modules/@esbuild/aix-ppc64": {
320
+ "version": "0.21.5",
321
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
322
+ "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
323
+ "cpu": [
324
+ "ppc64"
325
+ ],
326
+ "dev": true,
327
+ "license": "MIT",
328
+ "optional": true,
329
+ "os": [
330
+ "aix"
331
+ ],
332
+ "engines": {
333
+ "node": ">=12"
334
+ }
335
+ },
336
+ "node_modules/@esbuild/android-arm": {
337
+ "version": "0.21.5",
338
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
339
+ "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
340
+ "cpu": [
341
+ "arm"
342
+ ],
343
+ "dev": true,
344
+ "license": "MIT",
345
+ "optional": true,
346
+ "os": [
347
+ "android"
348
+ ],
349
+ "engines": {
350
+ "node": ">=12"
351
+ }
352
+ },
353
+ "node_modules/@esbuild/android-arm64": {
354
+ "version": "0.21.5",
355
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
356
+ "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
357
+ "cpu": [
358
+ "arm64"
359
+ ],
360
+ "dev": true,
361
+ "license": "MIT",
362
+ "optional": true,
363
+ "os": [
364
+ "android"
365
+ ],
366
+ "engines": {
367
+ "node": ">=12"
368
+ }
369
+ },
370
+ "node_modules/@esbuild/android-x64": {
371
+ "version": "0.21.5",
372
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
373
+ "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
374
+ "cpu": [
375
+ "x64"
376
+ ],
377
+ "dev": true,
378
+ "license": "MIT",
379
+ "optional": true,
380
+ "os": [
381
+ "android"
382
+ ],
383
+ "engines": {
384
+ "node": ">=12"
385
+ }
386
+ },
387
+ "node_modules/@esbuild/darwin-arm64": {
388
+ "version": "0.21.5",
389
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
390
+ "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
391
+ "cpu": [
392
+ "arm64"
393
+ ],
394
+ "dev": true,
395
+ "license": "MIT",
396
+ "optional": true,
397
+ "os": [
398
+ "darwin"
399
+ ],
400
+ "engines": {
401
+ "node": ">=12"
402
+ }
403
+ },
404
+ "node_modules/@esbuild/darwin-x64": {
405
+ "version": "0.21.5",
406
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
407
+ "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
408
+ "cpu": [
409
+ "x64"
410
+ ],
411
+ "dev": true,
412
+ "license": "MIT",
413
+ "optional": true,
414
+ "os": [
415
+ "darwin"
416
+ ],
417
+ "engines": {
418
+ "node": ">=12"
419
+ }
420
+ },
421
+ "node_modules/@esbuild/freebsd-arm64": {
422
+ "version": "0.21.5",
423
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
424
+ "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
425
+ "cpu": [
426
+ "arm64"
427
+ ],
428
+ "dev": true,
429
+ "license": "MIT",
430
+ "optional": true,
431
+ "os": [
432
+ "freebsd"
433
+ ],
434
+ "engines": {
435
+ "node": ">=12"
436
+ }
437
+ },
438
+ "node_modules/@esbuild/freebsd-x64": {
439
+ "version": "0.21.5",
440
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
441
+ "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
442
+ "cpu": [
443
+ "x64"
444
+ ],
445
+ "dev": true,
446
+ "license": "MIT",
447
+ "optional": true,
448
+ "os": [
449
+ "freebsd"
450
+ ],
451
+ "engines": {
452
+ "node": ">=12"
453
+ }
454
+ },
455
+ "node_modules/@esbuild/linux-arm": {
456
+ "version": "0.21.5",
457
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
458
+ "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
459
+ "cpu": [
460
+ "arm"
461
+ ],
462
+ "dev": true,
463
+ "license": "MIT",
464
+ "optional": true,
465
+ "os": [
466
+ "linux"
467
+ ],
468
+ "engines": {
469
+ "node": ">=12"
470
+ }
471
+ },
472
+ "node_modules/@esbuild/linux-arm64": {
473
+ "version": "0.21.5",
474
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
475
+ "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
476
+ "cpu": [
477
+ "arm64"
478
+ ],
479
+ "dev": true,
480
+ "license": "MIT",
481
+ "optional": true,
482
+ "os": [
483
+ "linux"
484
+ ],
485
+ "engines": {
486
+ "node": ">=12"
487
+ }
488
+ },
489
+ "node_modules/@esbuild/linux-ia32": {
490
+ "version": "0.21.5",
491
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
492
+ "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
493
+ "cpu": [
494
+ "ia32"
495
+ ],
496
+ "dev": true,
497
+ "license": "MIT",
498
+ "optional": true,
499
+ "os": [
500
+ "linux"
501
+ ],
502
+ "engines": {
503
+ "node": ">=12"
504
+ }
505
+ },
506
+ "node_modules/@esbuild/linux-loong64": {
507
+ "version": "0.21.5",
508
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
509
+ "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
510
+ "cpu": [
511
+ "loong64"
512
+ ],
513
+ "dev": true,
514
+ "license": "MIT",
515
+ "optional": true,
516
+ "os": [
517
+ "linux"
518
+ ],
519
+ "engines": {
520
+ "node": ">=12"
521
+ }
522
+ },
523
+ "node_modules/@esbuild/linux-mips64el": {
524
+ "version": "0.21.5",
525
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
526
+ "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
527
+ "cpu": [
528
+ "mips64el"
529
+ ],
530
+ "dev": true,
531
+ "license": "MIT",
532
+ "optional": true,
533
+ "os": [
534
+ "linux"
535
+ ],
536
+ "engines": {
537
+ "node": ">=12"
538
+ }
539
+ },
540
+ "node_modules/@esbuild/linux-ppc64": {
541
+ "version": "0.21.5",
542
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
543
+ "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
544
+ "cpu": [
545
+ "ppc64"
546
+ ],
547
+ "dev": true,
548
+ "license": "MIT",
549
+ "optional": true,
550
+ "os": [
551
+ "linux"
552
+ ],
553
+ "engines": {
554
+ "node": ">=12"
555
+ }
556
+ },
557
+ "node_modules/@esbuild/linux-riscv64": {
558
+ "version": "0.21.5",
559
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
560
+ "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
561
+ "cpu": [
562
+ "riscv64"
563
+ ],
564
+ "dev": true,
565
+ "license": "MIT",
566
+ "optional": true,
567
+ "os": [
568
+ "linux"
569
+ ],
570
+ "engines": {
571
+ "node": ">=12"
572
+ }
573
+ },
574
+ "node_modules/@esbuild/linux-s390x": {
575
+ "version": "0.21.5",
576
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
577
+ "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
578
+ "cpu": [
579
+ "s390x"
580
+ ],
581
+ "dev": true,
582
+ "license": "MIT",
583
+ "optional": true,
584
+ "os": [
585
+ "linux"
586
+ ],
587
+ "engines": {
588
+ "node": ">=12"
589
+ }
590
+ },
591
+ "node_modules/@esbuild/linux-x64": {
592
+ "version": "0.21.5",
593
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
594
+ "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
595
+ "cpu": [
596
+ "x64"
597
+ ],
598
+ "dev": true,
599
+ "license": "MIT",
600
+ "optional": true,
601
+ "os": [
602
+ "linux"
603
+ ],
604
+ "engines": {
605
+ "node": ">=12"
606
+ }
607
+ },
608
+ "node_modules/@esbuild/netbsd-x64": {
609
+ "version": "0.21.5",
610
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
611
+ "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
612
+ "cpu": [
613
+ "x64"
614
+ ],
615
+ "dev": true,
616
+ "license": "MIT",
617
+ "optional": true,
618
+ "os": [
619
+ "netbsd"
620
+ ],
621
+ "engines": {
622
+ "node": ">=12"
623
+ }
624
+ },
625
+ "node_modules/@esbuild/openbsd-x64": {
626
+ "version": "0.21.5",
627
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
628
+ "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
629
+ "cpu": [
630
+ "x64"
631
+ ],
632
+ "dev": true,
633
+ "license": "MIT",
634
+ "optional": true,
635
+ "os": [
636
+ "openbsd"
637
+ ],
638
+ "engines": {
639
+ "node": ">=12"
640
+ }
641
+ },
642
+ "node_modules/@esbuild/sunos-x64": {
643
+ "version": "0.21.5",
644
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
645
+ "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
646
+ "cpu": [
647
+ "x64"
648
+ ],
649
+ "dev": true,
650
+ "license": "MIT",
651
+ "optional": true,
652
+ "os": [
653
+ "sunos"
654
+ ],
655
+ "engines": {
656
+ "node": ">=12"
657
+ }
658
+ },
659
+ "node_modules/@esbuild/win32-arm64": {
660
+ "version": "0.21.5",
661
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
662
+ "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
663
+ "cpu": [
664
+ "arm64"
665
+ ],
666
+ "dev": true,
667
+ "license": "MIT",
668
+ "optional": true,
669
+ "os": [
670
+ "win32"
671
+ ],
672
+ "engines": {
673
+ "node": ">=12"
674
+ }
675
+ },
676
+ "node_modules/@esbuild/win32-ia32": {
677
+ "version": "0.21.5",
678
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
679
+ "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
680
+ "cpu": [
681
+ "ia32"
682
+ ],
683
+ "dev": true,
684
+ "license": "MIT",
685
+ "optional": true,
686
+ "os": [
687
+ "win32"
688
+ ],
689
+ "engines": {
690
+ "node": ">=12"
691
+ }
692
+ },
693
+ "node_modules/@esbuild/win32-x64": {
694
+ "version": "0.21.5",
695
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
696
+ "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
697
+ "cpu": [
698
+ "x64"
699
+ ],
700
+ "dev": true,
701
+ "license": "MIT",
702
+ "optional": true,
703
+ "os": [
704
+ "win32"
705
+ ],
706
+ "engines": {
707
+ "node": ">=12"
708
+ }
709
+ },
710
+ "node_modules/@jridgewell/gen-mapping": {
711
+ "version": "0.3.13",
712
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
713
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
714
+ "dev": true,
715
+ "license": "MIT",
716
+ "dependencies": {
717
+ "@jridgewell/sourcemap-codec": "^1.5.0",
718
+ "@jridgewell/trace-mapping": "^0.3.24"
719
+ }
720
+ },
721
+ "node_modules/@jridgewell/remapping": {
722
+ "version": "2.3.5",
723
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
724
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
725
+ "dev": true,
726
+ "license": "MIT",
727
+ "dependencies": {
728
+ "@jridgewell/gen-mapping": "^0.3.5",
729
+ "@jridgewell/trace-mapping": "^0.3.24"
730
+ }
731
+ },
732
+ "node_modules/@jridgewell/resolve-uri": {
733
+ "version": "3.1.2",
734
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
735
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
736
+ "dev": true,
737
+ "license": "MIT",
738
+ "engines": {
739
+ "node": ">=6.0.0"
740
+ }
741
+ },
742
+ "node_modules/@jridgewell/sourcemap-codec": {
743
+ "version": "1.5.5",
744
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
745
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
746
+ "dev": true,
747
+ "license": "MIT"
748
+ },
749
+ "node_modules/@jridgewell/trace-mapping": {
750
+ "version": "0.3.31",
751
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
752
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
753
+ "dev": true,
754
+ "license": "MIT",
755
+ "dependencies": {
756
+ "@jridgewell/resolve-uri": "^3.1.0",
757
+ "@jridgewell/sourcemap-codec": "^1.4.14"
758
+ }
759
+ },
760
+ "node_modules/@nodelib/fs.scandir": {
761
+ "version": "2.1.5",
762
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
763
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
764
+ "dev": true,
765
+ "license": "MIT",
766
+ "dependencies": {
767
+ "@nodelib/fs.stat": "2.0.5",
768
+ "run-parallel": "^1.1.9"
769
+ },
770
+ "engines": {
771
+ "node": ">= 8"
772
+ }
773
+ },
774
+ "node_modules/@nodelib/fs.stat": {
775
+ "version": "2.0.5",
776
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
777
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
778
+ "dev": true,
779
+ "license": "MIT",
780
+ "engines": {
781
+ "node": ">= 8"
782
+ }
783
+ },
784
+ "node_modules/@nodelib/fs.walk": {
785
+ "version": "1.2.8",
786
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
787
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
788
+ "dev": true,
789
+ "license": "MIT",
790
+ "dependencies": {
791
+ "@nodelib/fs.scandir": "2.1.5",
792
+ "fastq": "^1.6.0"
793
+ },
794
+ "engines": {
795
+ "node": ">= 8"
796
+ }
797
+ },
798
+ "node_modules/@rolldown/pluginutils": {
799
+ "version": "1.0.0-beta.27",
800
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
801
+ "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==",
802
+ "dev": true,
803
+ "license": "MIT"
804
+ },
805
+ "node_modules/@rollup/rollup-android-arm-eabi": {
806
+ "version": "4.59.0",
807
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz",
808
+ "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==",
809
+ "cpu": [
810
+ "arm"
811
+ ],
812
+ "dev": true,
813
+ "license": "MIT",
814
+ "optional": true,
815
+ "os": [
816
+ "android"
817
+ ]
818
+ },
819
+ "node_modules/@rollup/rollup-android-arm64": {
820
+ "version": "4.59.0",
821
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz",
822
+ "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==",
823
+ "cpu": [
824
+ "arm64"
825
+ ],
826
+ "dev": true,
827
+ "license": "MIT",
828
+ "optional": true,
829
+ "os": [
830
+ "android"
831
+ ]
832
+ },
833
+ "node_modules/@rollup/rollup-darwin-arm64": {
834
+ "version": "4.59.0",
835
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz",
836
+ "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==",
837
+ "cpu": [
838
+ "arm64"
839
+ ],
840
+ "dev": true,
841
+ "license": "MIT",
842
+ "optional": true,
843
+ "os": [
844
+ "darwin"
845
+ ]
846
+ },
847
+ "node_modules/@rollup/rollup-darwin-x64": {
848
+ "version": "4.59.0",
849
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz",
850
+ "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==",
851
+ "cpu": [
852
+ "x64"
853
+ ],
854
+ "dev": true,
855
+ "license": "MIT",
856
+ "optional": true,
857
+ "os": [
858
+ "darwin"
859
+ ]
860
+ },
861
+ "node_modules/@rollup/rollup-freebsd-arm64": {
862
+ "version": "4.59.0",
863
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz",
864
+ "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==",
865
+ "cpu": [
866
+ "arm64"
867
+ ],
868
+ "dev": true,
869
+ "license": "MIT",
870
+ "optional": true,
871
+ "os": [
872
+ "freebsd"
873
+ ]
874
+ },
875
+ "node_modules/@rollup/rollup-freebsd-x64": {
876
+ "version": "4.59.0",
877
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz",
878
+ "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==",
879
+ "cpu": [
880
+ "x64"
881
+ ],
882
+ "dev": true,
883
+ "license": "MIT",
884
+ "optional": true,
885
+ "os": [
886
+ "freebsd"
887
+ ]
888
+ },
889
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
890
+ "version": "4.59.0",
891
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz",
892
+ "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==",
893
+ "cpu": [
894
+ "arm"
895
+ ],
896
+ "dev": true,
897
+ "license": "MIT",
898
+ "optional": true,
899
+ "os": [
900
+ "linux"
901
+ ]
902
+ },
903
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
904
+ "version": "4.59.0",
905
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz",
906
+ "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==",
907
+ "cpu": [
908
+ "arm"
909
+ ],
910
+ "dev": true,
911
+ "license": "MIT",
912
+ "optional": true,
913
+ "os": [
914
+ "linux"
915
+ ]
916
+ },
917
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
918
+ "version": "4.59.0",
919
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz",
920
+ "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==",
921
+ "cpu": [
922
+ "arm64"
923
+ ],
924
+ "dev": true,
925
+ "license": "MIT",
926
+ "optional": true,
927
+ "os": [
928
+ "linux"
929
+ ]
930
+ },
931
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
932
+ "version": "4.59.0",
933
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz",
934
+ "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==",
935
+ "cpu": [
936
+ "arm64"
937
+ ],
938
+ "dev": true,
939
+ "license": "MIT",
940
+ "optional": true,
941
+ "os": [
942
+ "linux"
943
+ ]
944
+ },
945
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
946
+ "version": "4.59.0",
947
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz",
948
+ "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==",
949
+ "cpu": [
950
+ "loong64"
951
+ ],
952
+ "dev": true,
953
+ "license": "MIT",
954
+ "optional": true,
955
+ "os": [
956
+ "linux"
957
+ ]
958
+ },
959
+ "node_modules/@rollup/rollup-linux-loong64-musl": {
960
+ "version": "4.59.0",
961
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz",
962
+ "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==",
963
+ "cpu": [
964
+ "loong64"
965
+ ],
966
+ "dev": true,
967
+ "license": "MIT",
968
+ "optional": true,
969
+ "os": [
970
+ "linux"
971
+ ]
972
+ },
973
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
974
+ "version": "4.59.0",
975
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz",
976
+ "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==",
977
+ "cpu": [
978
+ "ppc64"
979
+ ],
980
+ "dev": true,
981
+ "license": "MIT",
982
+ "optional": true,
983
+ "os": [
984
+ "linux"
985
+ ]
986
+ },
987
+ "node_modules/@rollup/rollup-linux-ppc64-musl": {
988
+ "version": "4.59.0",
989
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz",
990
+ "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==",
991
+ "cpu": [
992
+ "ppc64"
993
+ ],
994
+ "dev": true,
995
+ "license": "MIT",
996
+ "optional": true,
997
+ "os": [
998
+ "linux"
999
+ ]
1000
+ },
1001
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
1002
+ "version": "4.59.0",
1003
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz",
1004
+ "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==",
1005
+ "cpu": [
1006
+ "riscv64"
1007
+ ],
1008
+ "dev": true,
1009
+ "license": "MIT",
1010
+ "optional": true,
1011
+ "os": [
1012
+ "linux"
1013
+ ]
1014
+ },
1015
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
1016
+ "version": "4.59.0",
1017
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz",
1018
+ "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==",
1019
+ "cpu": [
1020
+ "riscv64"
1021
+ ],
1022
+ "dev": true,
1023
+ "license": "MIT",
1024
+ "optional": true,
1025
+ "os": [
1026
+ "linux"
1027
+ ]
1028
+ },
1029
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
1030
+ "version": "4.59.0",
1031
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz",
1032
+ "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==",
1033
+ "cpu": [
1034
+ "s390x"
1035
+ ],
1036
+ "dev": true,
1037
+ "license": "MIT",
1038
+ "optional": true,
1039
+ "os": [
1040
+ "linux"
1041
+ ]
1042
+ },
1043
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
1044
+ "version": "4.59.0",
1045
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz",
1046
+ "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==",
1047
+ "cpu": [
1048
+ "x64"
1049
+ ],
1050
+ "dev": true,
1051
+ "license": "MIT",
1052
+ "optional": true,
1053
+ "os": [
1054
+ "linux"
1055
+ ]
1056
+ },
1057
+ "node_modules/@rollup/rollup-linux-x64-musl": {
1058
+ "version": "4.59.0",
1059
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz",
1060
+ "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==",
1061
+ "cpu": [
1062
+ "x64"
1063
+ ],
1064
+ "dev": true,
1065
+ "license": "MIT",
1066
+ "optional": true,
1067
+ "os": [
1068
+ "linux"
1069
+ ]
1070
+ },
1071
+ "node_modules/@rollup/rollup-openbsd-x64": {
1072
+ "version": "4.59.0",
1073
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz",
1074
+ "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==",
1075
+ "cpu": [
1076
+ "x64"
1077
+ ],
1078
+ "dev": true,
1079
+ "license": "MIT",
1080
+ "optional": true,
1081
+ "os": [
1082
+ "openbsd"
1083
+ ]
1084
+ },
1085
+ "node_modules/@rollup/rollup-openharmony-arm64": {
1086
+ "version": "4.59.0",
1087
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz",
1088
+ "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==",
1089
+ "cpu": [
1090
+ "arm64"
1091
+ ],
1092
+ "dev": true,
1093
+ "license": "MIT",
1094
+ "optional": true,
1095
+ "os": [
1096
+ "openharmony"
1097
+ ]
1098
+ },
1099
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
1100
+ "version": "4.59.0",
1101
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz",
1102
+ "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==",
1103
+ "cpu": [
1104
+ "arm64"
1105
+ ],
1106
+ "dev": true,
1107
+ "license": "MIT",
1108
+ "optional": true,
1109
+ "os": [
1110
+ "win32"
1111
+ ]
1112
+ },
1113
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
1114
+ "version": "4.59.0",
1115
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz",
1116
+ "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==",
1117
+ "cpu": [
1118
+ "ia32"
1119
+ ],
1120
+ "dev": true,
1121
+ "license": "MIT",
1122
+ "optional": true,
1123
+ "os": [
1124
+ "win32"
1125
+ ]
1126
+ },
1127
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
1128
+ "version": "4.59.0",
1129
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz",
1130
+ "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==",
1131
+ "cpu": [
1132
+ "x64"
1133
+ ],
1134
+ "dev": true,
1135
+ "license": "MIT",
1136
+ "optional": true,
1137
+ "os": [
1138
+ "win32"
1139
+ ]
1140
+ },
1141
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
1142
+ "version": "4.59.0",
1143
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz",
1144
+ "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==",
1145
+ "cpu": [
1146
+ "x64"
1147
+ ],
1148
+ "dev": true,
1149
+ "license": "MIT",
1150
+ "optional": true,
1151
+ "os": [
1152
+ "win32"
1153
+ ]
1154
+ },
1155
+ "node_modules/@types/babel__core": {
1156
+ "version": "7.20.5",
1157
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
1158
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
1159
+ "dev": true,
1160
+ "license": "MIT",
1161
+ "dependencies": {
1162
+ "@babel/parser": "^7.20.7",
1163
+ "@babel/types": "^7.20.7",
1164
+ "@types/babel__generator": "*",
1165
+ "@types/babel__template": "*",
1166
+ "@types/babel__traverse": "*"
1167
+ }
1168
+ },
1169
+ "node_modules/@types/babel__generator": {
1170
+ "version": "7.27.0",
1171
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
1172
+ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
1173
+ "dev": true,
1174
+ "license": "MIT",
1175
+ "dependencies": {
1176
+ "@babel/types": "^7.0.0"
1177
+ }
1178
+ },
1179
+ "node_modules/@types/babel__template": {
1180
+ "version": "7.4.4",
1181
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
1182
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
1183
+ "dev": true,
1184
+ "license": "MIT",
1185
+ "dependencies": {
1186
+ "@babel/parser": "^7.1.0",
1187
+ "@babel/types": "^7.0.0"
1188
+ }
1189
+ },
1190
+ "node_modules/@types/babel__traverse": {
1191
+ "version": "7.28.0",
1192
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
1193
+ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
1194
+ "dev": true,
1195
+ "license": "MIT",
1196
+ "dependencies": {
1197
+ "@babel/types": "^7.28.2"
1198
+ }
1199
+ },
1200
+ "node_modules/@types/estree": {
1201
+ "version": "1.0.8",
1202
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
1203
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
1204
+ "dev": true,
1205
+ "license": "MIT"
1206
+ },
1207
+ "node_modules/@vitejs/plugin-react": {
1208
+ "version": "4.7.0",
1209
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
1210
+ "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==",
1211
+ "dev": true,
1212
+ "license": "MIT",
1213
+ "dependencies": {
1214
+ "@babel/core": "^7.28.0",
1215
+ "@babel/plugin-transform-react-jsx-self": "^7.27.1",
1216
+ "@babel/plugin-transform-react-jsx-source": "^7.27.1",
1217
+ "@rolldown/pluginutils": "1.0.0-beta.27",
1218
+ "@types/babel__core": "^7.20.5",
1219
+ "react-refresh": "^0.17.0"
1220
+ },
1221
+ "engines": {
1222
+ "node": "^14.18.0 || >=16.0.0"
1223
+ },
1224
+ "peerDependencies": {
1225
+ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
1226
+ }
1227
+ },
1228
+ "node_modules/any-promise": {
1229
+ "version": "1.3.0",
1230
+ "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
1231
+ "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
1232
+ "dev": true,
1233
+ "license": "MIT"
1234
+ },
1235
+ "node_modules/anymatch": {
1236
+ "version": "3.1.3",
1237
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
1238
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
1239
+ "dev": true,
1240
+ "license": "ISC",
1241
+ "dependencies": {
1242
+ "normalize-path": "^3.0.0",
1243
+ "picomatch": "^2.0.4"
1244
+ },
1245
+ "engines": {
1246
+ "node": ">= 8"
1247
+ }
1248
+ },
1249
+ "node_modules/arg": {
1250
+ "version": "5.0.2",
1251
+ "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
1252
+ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
1253
+ "dev": true,
1254
+ "license": "MIT"
1255
+ },
1256
+ "node_modules/asynckit": {
1257
+ "version": "0.4.0",
1258
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
1259
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
1260
+ "license": "MIT"
1261
+ },
1262
+ "node_modules/autoprefixer": {
1263
+ "version": "10.4.27",
1264
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.27.tgz",
1265
+ "integrity": "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==",
1266
+ "dev": true,
1267
+ "funding": [
1268
+ {
1269
+ "type": "opencollective",
1270
+ "url": "https://opencollective.com/postcss/"
1271
+ },
1272
+ {
1273
+ "type": "tidelift",
1274
+ "url": "https://tidelift.com/funding/github/npm/autoprefixer"
1275
+ },
1276
+ {
1277
+ "type": "github",
1278
+ "url": "https://github.com/sponsors/ai"
1279
+ }
1280
+ ],
1281
+ "license": "MIT",
1282
+ "dependencies": {
1283
+ "browserslist": "^4.28.1",
1284
+ "caniuse-lite": "^1.0.30001774",
1285
+ "fraction.js": "^5.3.4",
1286
+ "picocolors": "^1.1.1",
1287
+ "postcss-value-parser": "^4.2.0"
1288
+ },
1289
+ "bin": {
1290
+ "autoprefixer": "bin/autoprefixer"
1291
+ },
1292
+ "engines": {
1293
+ "node": "^10 || ^12 || >=14"
1294
+ },
1295
+ "peerDependencies": {
1296
+ "postcss": "^8.1.0"
1297
+ }
1298
+ },
1299
+ "node_modules/axios": {
1300
+ "version": "1.13.6",
1301
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz",
1302
+ "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==",
1303
+ "license": "MIT",
1304
+ "dependencies": {
1305
+ "follow-redirects": "^1.15.11",
1306
+ "form-data": "^4.0.5",
1307
+ "proxy-from-env": "^1.1.0"
1308
+ }
1309
+ },
1310
+ "node_modules/baseline-browser-mapping": {
1311
+ "version": "2.10.8",
1312
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.8.tgz",
1313
+ "integrity": "sha512-PCLz/LXGBsNTErbtB6i5u4eLpHeMfi93aUv5duMmj6caNu6IphS4q6UevDnL36sZQv9lrP11dbPKGMaXPwMKfQ==",
1314
+ "dev": true,
1315
+ "license": "Apache-2.0",
1316
+ "bin": {
1317
+ "baseline-browser-mapping": "dist/cli.cjs"
1318
+ },
1319
+ "engines": {
1320
+ "node": ">=6.0.0"
1321
+ }
1322
+ },
1323
+ "node_modules/binary-extensions": {
1324
+ "version": "2.3.0",
1325
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
1326
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
1327
+ "dev": true,
1328
+ "license": "MIT",
1329
+ "engines": {
1330
+ "node": ">=8"
1331
+ },
1332
+ "funding": {
1333
+ "url": "https://github.com/sponsors/sindresorhus"
1334
+ }
1335
+ },
1336
+ "node_modules/braces": {
1337
+ "version": "3.0.3",
1338
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
1339
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
1340
+ "dev": true,
1341
+ "license": "MIT",
1342
+ "dependencies": {
1343
+ "fill-range": "^7.1.1"
1344
+ },
1345
+ "engines": {
1346
+ "node": ">=8"
1347
+ }
1348
+ },
1349
+ "node_modules/browserslist": {
1350
+ "version": "4.28.1",
1351
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
1352
+ "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
1353
+ "dev": true,
1354
+ "funding": [
1355
+ {
1356
+ "type": "opencollective",
1357
+ "url": "https://opencollective.com/browserslist"
1358
+ },
1359
+ {
1360
+ "type": "tidelift",
1361
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
1362
+ },
1363
+ {
1364
+ "type": "github",
1365
+ "url": "https://github.com/sponsors/ai"
1366
+ }
1367
+ ],
1368
+ "license": "MIT",
1369
+ "dependencies": {
1370
+ "baseline-browser-mapping": "^2.9.0",
1371
+ "caniuse-lite": "^1.0.30001759",
1372
+ "electron-to-chromium": "^1.5.263",
1373
+ "node-releases": "^2.0.27",
1374
+ "update-browserslist-db": "^1.2.0"
1375
+ },
1376
+ "bin": {
1377
+ "browserslist": "cli.js"
1378
+ },
1379
+ "engines": {
1380
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
1381
+ }
1382
+ },
1383
+ "node_modules/call-bind-apply-helpers": {
1384
+ "version": "1.0.2",
1385
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
1386
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
1387
+ "license": "MIT",
1388
+ "dependencies": {
1389
+ "es-errors": "^1.3.0",
1390
+ "function-bind": "^1.1.2"
1391
+ },
1392
+ "engines": {
1393
+ "node": ">= 0.4"
1394
+ }
1395
+ },
1396
+ "node_modules/camelcase-css": {
1397
+ "version": "2.0.1",
1398
+ "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
1399
+ "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
1400
+ "dev": true,
1401
+ "license": "MIT",
1402
+ "engines": {
1403
+ "node": ">= 6"
1404
+ }
1405
+ },
1406
+ "node_modules/caniuse-lite": {
1407
+ "version": "1.0.30001779",
1408
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001779.tgz",
1409
+ "integrity": "sha512-U5og2PN7V4DMgF50YPNtnZJGWVLFjjsN3zb6uMT5VGYIewieDj1upwfuVNXf4Kor+89c3iCRJnSzMD5LmTvsfA==",
1410
+ "dev": true,
1411
+ "funding": [
1412
+ {
1413
+ "type": "opencollective",
1414
+ "url": "https://opencollective.com/browserslist"
1415
+ },
1416
+ {
1417
+ "type": "tidelift",
1418
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
1419
+ },
1420
+ {
1421
+ "type": "github",
1422
+ "url": "https://github.com/sponsors/ai"
1423
+ }
1424
+ ],
1425
+ "license": "CC-BY-4.0"
1426
+ },
1427
+ "node_modules/chokidar": {
1428
+ "version": "3.6.0",
1429
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
1430
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
1431
+ "dev": true,
1432
+ "license": "MIT",
1433
+ "dependencies": {
1434
+ "anymatch": "~3.1.2",
1435
+ "braces": "~3.0.2",
1436
+ "glob-parent": "~5.1.2",
1437
+ "is-binary-path": "~2.1.0",
1438
+ "is-glob": "~4.0.1",
1439
+ "normalize-path": "~3.0.0",
1440
+ "readdirp": "~3.6.0"
1441
+ },
1442
+ "engines": {
1443
+ "node": ">= 8.10.0"
1444
+ },
1445
+ "funding": {
1446
+ "url": "https://paulmillr.com/funding/"
1447
+ },
1448
+ "optionalDependencies": {
1449
+ "fsevents": "~2.3.2"
1450
+ }
1451
+ },
1452
+ "node_modules/chokidar/node_modules/glob-parent": {
1453
+ "version": "5.1.2",
1454
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
1455
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
1456
+ "dev": true,
1457
+ "license": "ISC",
1458
+ "dependencies": {
1459
+ "is-glob": "^4.0.1"
1460
+ },
1461
+ "engines": {
1462
+ "node": ">= 6"
1463
+ }
1464
+ },
1465
+ "node_modules/combined-stream": {
1466
+ "version": "1.0.8",
1467
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
1468
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
1469
+ "license": "MIT",
1470
+ "dependencies": {
1471
+ "delayed-stream": "~1.0.0"
1472
+ },
1473
+ "engines": {
1474
+ "node": ">= 0.8"
1475
+ }
1476
+ },
1477
+ "node_modules/commander": {
1478
+ "version": "4.1.1",
1479
+ "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
1480
+ "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
1481
+ "dev": true,
1482
+ "license": "MIT",
1483
+ "engines": {
1484
+ "node": ">= 6"
1485
+ }
1486
+ },
1487
+ "node_modules/convert-source-map": {
1488
+ "version": "2.0.0",
1489
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
1490
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
1491
+ "dev": true,
1492
+ "license": "MIT"
1493
+ },
1494
+ "node_modules/cssesc": {
1495
+ "version": "3.0.0",
1496
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
1497
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
1498
+ "dev": true,
1499
+ "license": "MIT",
1500
+ "bin": {
1501
+ "cssesc": "bin/cssesc"
1502
+ },
1503
+ "engines": {
1504
+ "node": ">=4"
1505
+ }
1506
+ },
1507
+ "node_modules/debug": {
1508
+ "version": "4.4.3",
1509
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
1510
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
1511
+ "dev": true,
1512
+ "license": "MIT",
1513
+ "dependencies": {
1514
+ "ms": "^2.1.3"
1515
+ },
1516
+ "engines": {
1517
+ "node": ">=6.0"
1518
+ },
1519
+ "peerDependenciesMeta": {
1520
+ "supports-color": {
1521
+ "optional": true
1522
+ }
1523
+ }
1524
+ },
1525
+ "node_modules/delayed-stream": {
1526
+ "version": "1.0.0",
1527
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
1528
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
1529
+ "license": "MIT",
1530
+ "engines": {
1531
+ "node": ">=0.4.0"
1532
+ }
1533
+ },
1534
+ "node_modules/didyoumean": {
1535
+ "version": "1.2.2",
1536
+ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
1537
+ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
1538
+ "dev": true,
1539
+ "license": "Apache-2.0"
1540
+ },
1541
+ "node_modules/dlv": {
1542
+ "version": "1.1.3",
1543
+ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
1544
+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
1545
+ "dev": true,
1546
+ "license": "MIT"
1547
+ },
1548
+ "node_modules/dunder-proto": {
1549
+ "version": "1.0.1",
1550
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
1551
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
1552
+ "license": "MIT",
1553
+ "dependencies": {
1554
+ "call-bind-apply-helpers": "^1.0.1",
1555
+ "es-errors": "^1.3.0",
1556
+ "gopd": "^1.2.0"
1557
+ },
1558
+ "engines": {
1559
+ "node": ">= 0.4"
1560
+ }
1561
+ },
1562
+ "node_modules/electron-to-chromium": {
1563
+ "version": "1.5.313",
1564
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.313.tgz",
1565
+ "integrity": "sha512-QBMrTWEf00GXZmJyx2lbYD45jpI3TUFnNIzJ5BBc8piGUDwMPa1GV6HJWTZVvY/eiN3fSopl7NRbgGp9sZ9LTA==",
1566
+ "dev": true,
1567
+ "license": "ISC"
1568
+ },
1569
+ "node_modules/es-define-property": {
1570
+ "version": "1.0.1",
1571
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
1572
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
1573
+ "license": "MIT",
1574
+ "engines": {
1575
+ "node": ">= 0.4"
1576
+ }
1577
+ },
1578
+ "node_modules/es-errors": {
1579
+ "version": "1.3.0",
1580
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
1581
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
1582
+ "license": "MIT",
1583
+ "engines": {
1584
+ "node": ">= 0.4"
1585
+ }
1586
+ },
1587
+ "node_modules/es-object-atoms": {
1588
+ "version": "1.1.1",
1589
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
1590
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
1591
+ "license": "MIT",
1592
+ "dependencies": {
1593
+ "es-errors": "^1.3.0"
1594
+ },
1595
+ "engines": {
1596
+ "node": ">= 0.4"
1597
+ }
1598
+ },
1599
+ "node_modules/es-set-tostringtag": {
1600
+ "version": "2.1.0",
1601
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
1602
+ "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
1603
+ "license": "MIT",
1604
+ "dependencies": {
1605
+ "es-errors": "^1.3.0",
1606
+ "get-intrinsic": "^1.2.6",
1607
+ "has-tostringtag": "^1.0.2",
1608
+ "hasown": "^2.0.2"
1609
+ },
1610
+ "engines": {
1611
+ "node": ">= 0.4"
1612
+ }
1613
+ },
1614
+ "node_modules/esbuild": {
1615
+ "version": "0.21.5",
1616
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
1617
+ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
1618
+ "dev": true,
1619
+ "hasInstallScript": true,
1620
+ "license": "MIT",
1621
+ "bin": {
1622
+ "esbuild": "bin/esbuild"
1623
+ },
1624
+ "engines": {
1625
+ "node": ">=12"
1626
+ },
1627
+ "optionalDependencies": {
1628
+ "@esbuild/aix-ppc64": "0.21.5",
1629
+ "@esbuild/android-arm": "0.21.5",
1630
+ "@esbuild/android-arm64": "0.21.5",
1631
+ "@esbuild/android-x64": "0.21.5",
1632
+ "@esbuild/darwin-arm64": "0.21.5",
1633
+ "@esbuild/darwin-x64": "0.21.5",
1634
+ "@esbuild/freebsd-arm64": "0.21.5",
1635
+ "@esbuild/freebsd-x64": "0.21.5",
1636
+ "@esbuild/linux-arm": "0.21.5",
1637
+ "@esbuild/linux-arm64": "0.21.5",
1638
+ "@esbuild/linux-ia32": "0.21.5",
1639
+ "@esbuild/linux-loong64": "0.21.5",
1640
+ "@esbuild/linux-mips64el": "0.21.5",
1641
+ "@esbuild/linux-ppc64": "0.21.5",
1642
+ "@esbuild/linux-riscv64": "0.21.5",
1643
+ "@esbuild/linux-s390x": "0.21.5",
1644
+ "@esbuild/linux-x64": "0.21.5",
1645
+ "@esbuild/netbsd-x64": "0.21.5",
1646
+ "@esbuild/openbsd-x64": "0.21.5",
1647
+ "@esbuild/sunos-x64": "0.21.5",
1648
+ "@esbuild/win32-arm64": "0.21.5",
1649
+ "@esbuild/win32-ia32": "0.21.5",
1650
+ "@esbuild/win32-x64": "0.21.5"
1651
+ }
1652
+ },
1653
+ "node_modules/escalade": {
1654
+ "version": "3.2.0",
1655
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
1656
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
1657
+ "dev": true,
1658
+ "license": "MIT",
1659
+ "engines": {
1660
+ "node": ">=6"
1661
+ }
1662
+ },
1663
+ "node_modules/fast-glob": {
1664
+ "version": "3.3.3",
1665
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
1666
+ "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
1667
+ "dev": true,
1668
+ "license": "MIT",
1669
+ "dependencies": {
1670
+ "@nodelib/fs.stat": "^2.0.2",
1671
+ "@nodelib/fs.walk": "^1.2.3",
1672
+ "glob-parent": "^5.1.2",
1673
+ "merge2": "^1.3.0",
1674
+ "micromatch": "^4.0.8"
1675
+ },
1676
+ "engines": {
1677
+ "node": ">=8.6.0"
1678
+ }
1679
+ },
1680
+ "node_modules/fast-glob/node_modules/glob-parent": {
1681
+ "version": "5.1.2",
1682
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
1683
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
1684
+ "dev": true,
1685
+ "license": "ISC",
1686
+ "dependencies": {
1687
+ "is-glob": "^4.0.1"
1688
+ },
1689
+ "engines": {
1690
+ "node": ">= 6"
1691
+ }
1692
+ },
1693
+ "node_modules/fastq": {
1694
+ "version": "1.20.1",
1695
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
1696
+ "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
1697
+ "dev": true,
1698
+ "license": "ISC",
1699
+ "dependencies": {
1700
+ "reusify": "^1.0.4"
1701
+ }
1702
+ },
1703
+ "node_modules/fill-range": {
1704
+ "version": "7.1.1",
1705
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
1706
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
1707
+ "dev": true,
1708
+ "license": "MIT",
1709
+ "dependencies": {
1710
+ "to-regex-range": "^5.0.1"
1711
+ },
1712
+ "engines": {
1713
+ "node": ">=8"
1714
+ }
1715
+ },
1716
+ "node_modules/follow-redirects": {
1717
+ "version": "1.15.11",
1718
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
1719
+ "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
1720
+ "funding": [
1721
+ {
1722
+ "type": "individual",
1723
+ "url": "https://github.com/sponsors/RubenVerborgh"
1724
+ }
1725
+ ],
1726
+ "license": "MIT",
1727
+ "engines": {
1728
+ "node": ">=4.0"
1729
+ },
1730
+ "peerDependenciesMeta": {
1731
+ "debug": {
1732
+ "optional": true
1733
+ }
1734
+ }
1735
+ },
1736
+ "node_modules/form-data": {
1737
+ "version": "4.0.5",
1738
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
1739
+ "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
1740
+ "license": "MIT",
1741
+ "dependencies": {
1742
+ "asynckit": "^0.4.0",
1743
+ "combined-stream": "^1.0.8",
1744
+ "es-set-tostringtag": "^2.1.0",
1745
+ "hasown": "^2.0.2",
1746
+ "mime-types": "^2.1.12"
1747
+ },
1748
+ "engines": {
1749
+ "node": ">= 6"
1750
+ }
1751
+ },
1752
+ "node_modules/fraction.js": {
1753
+ "version": "5.3.4",
1754
+ "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz",
1755
+ "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==",
1756
+ "dev": true,
1757
+ "license": "MIT",
1758
+ "engines": {
1759
+ "node": "*"
1760
+ },
1761
+ "funding": {
1762
+ "type": "github",
1763
+ "url": "https://github.com/sponsors/rawify"
1764
+ }
1765
+ },
1766
+ "node_modules/fsevents": {
1767
+ "version": "2.3.3",
1768
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
1769
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
1770
+ "dev": true,
1771
+ "hasInstallScript": true,
1772
+ "license": "MIT",
1773
+ "optional": true,
1774
+ "os": [
1775
+ "darwin"
1776
+ ],
1777
+ "engines": {
1778
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
1779
+ }
1780
+ },
1781
+ "node_modules/function-bind": {
1782
+ "version": "1.1.2",
1783
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
1784
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
1785
+ "license": "MIT",
1786
+ "funding": {
1787
+ "url": "https://github.com/sponsors/ljharb"
1788
+ }
1789
+ },
1790
+ "node_modules/gensync": {
1791
+ "version": "1.0.0-beta.2",
1792
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
1793
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
1794
+ "dev": true,
1795
+ "license": "MIT",
1796
+ "engines": {
1797
+ "node": ">=6.9.0"
1798
+ }
1799
+ },
1800
+ "node_modules/get-intrinsic": {
1801
+ "version": "1.3.0",
1802
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
1803
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
1804
+ "license": "MIT",
1805
+ "dependencies": {
1806
+ "call-bind-apply-helpers": "^1.0.2",
1807
+ "es-define-property": "^1.0.1",
1808
+ "es-errors": "^1.3.0",
1809
+ "es-object-atoms": "^1.1.1",
1810
+ "function-bind": "^1.1.2",
1811
+ "get-proto": "^1.0.1",
1812
+ "gopd": "^1.2.0",
1813
+ "has-symbols": "^1.1.0",
1814
+ "hasown": "^2.0.2",
1815
+ "math-intrinsics": "^1.1.0"
1816
+ },
1817
+ "engines": {
1818
+ "node": ">= 0.4"
1819
+ },
1820
+ "funding": {
1821
+ "url": "https://github.com/sponsors/ljharb"
1822
+ }
1823
+ },
1824
+ "node_modules/get-proto": {
1825
+ "version": "1.0.1",
1826
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
1827
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
1828
+ "license": "MIT",
1829
+ "dependencies": {
1830
+ "dunder-proto": "^1.0.1",
1831
+ "es-object-atoms": "^1.0.0"
1832
+ },
1833
+ "engines": {
1834
+ "node": ">= 0.4"
1835
+ }
1836
+ },
1837
+ "node_modules/glob-parent": {
1838
+ "version": "6.0.2",
1839
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
1840
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
1841
+ "dev": true,
1842
+ "license": "ISC",
1843
+ "dependencies": {
1844
+ "is-glob": "^4.0.3"
1845
+ },
1846
+ "engines": {
1847
+ "node": ">=10.13.0"
1848
+ }
1849
+ },
1850
+ "node_modules/gopd": {
1851
+ "version": "1.2.0",
1852
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
1853
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
1854
+ "license": "MIT",
1855
+ "engines": {
1856
+ "node": ">= 0.4"
1857
+ },
1858
+ "funding": {
1859
+ "url": "https://github.com/sponsors/ljharb"
1860
+ }
1861
+ },
1862
+ "node_modules/has-symbols": {
1863
+ "version": "1.1.0",
1864
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
1865
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
1866
+ "license": "MIT",
1867
+ "engines": {
1868
+ "node": ">= 0.4"
1869
+ },
1870
+ "funding": {
1871
+ "url": "https://github.com/sponsors/ljharb"
1872
+ }
1873
+ },
1874
+ "node_modules/has-tostringtag": {
1875
+ "version": "1.0.2",
1876
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
1877
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
1878
+ "license": "MIT",
1879
+ "dependencies": {
1880
+ "has-symbols": "^1.0.3"
1881
+ },
1882
+ "engines": {
1883
+ "node": ">= 0.4"
1884
+ },
1885
+ "funding": {
1886
+ "url": "https://github.com/sponsors/ljharb"
1887
+ }
1888
+ },
1889
+ "node_modules/hasown": {
1890
+ "version": "2.0.2",
1891
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
1892
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
1893
+ "license": "MIT",
1894
+ "dependencies": {
1895
+ "function-bind": "^1.1.2"
1896
+ },
1897
+ "engines": {
1898
+ "node": ">= 0.4"
1899
+ }
1900
+ },
1901
+ "node_modules/is-binary-path": {
1902
+ "version": "2.1.0",
1903
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
1904
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
1905
+ "dev": true,
1906
+ "license": "MIT",
1907
+ "dependencies": {
1908
+ "binary-extensions": "^2.0.0"
1909
+ },
1910
+ "engines": {
1911
+ "node": ">=8"
1912
+ }
1913
+ },
1914
+ "node_modules/is-core-module": {
1915
+ "version": "2.16.1",
1916
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
1917
+ "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
1918
+ "dev": true,
1919
+ "license": "MIT",
1920
+ "dependencies": {
1921
+ "hasown": "^2.0.2"
1922
+ },
1923
+ "engines": {
1924
+ "node": ">= 0.4"
1925
+ },
1926
+ "funding": {
1927
+ "url": "https://github.com/sponsors/ljharb"
1928
+ }
1929
+ },
1930
+ "node_modules/is-extglob": {
1931
+ "version": "2.1.1",
1932
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
1933
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
1934
+ "dev": true,
1935
+ "license": "MIT",
1936
+ "engines": {
1937
+ "node": ">=0.10.0"
1938
+ }
1939
+ },
1940
+ "node_modules/is-glob": {
1941
+ "version": "4.0.3",
1942
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
1943
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
1944
+ "dev": true,
1945
+ "license": "MIT",
1946
+ "dependencies": {
1947
+ "is-extglob": "^2.1.1"
1948
+ },
1949
+ "engines": {
1950
+ "node": ">=0.10.0"
1951
+ }
1952
+ },
1953
+ "node_modules/is-number": {
1954
+ "version": "7.0.0",
1955
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
1956
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
1957
+ "dev": true,
1958
+ "license": "MIT",
1959
+ "engines": {
1960
+ "node": ">=0.12.0"
1961
+ }
1962
+ },
1963
+ "node_modules/jiti": {
1964
+ "version": "1.21.7",
1965
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
1966
+ "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
1967
+ "dev": true,
1968
+ "license": "MIT",
1969
+ "bin": {
1970
+ "jiti": "bin/jiti.js"
1971
+ }
1972
+ },
1973
+ "node_modules/js-tokens": {
1974
+ "version": "4.0.0",
1975
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
1976
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
1977
+ "license": "MIT"
1978
+ },
1979
+ "node_modules/jsesc": {
1980
+ "version": "3.1.0",
1981
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
1982
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
1983
+ "dev": true,
1984
+ "license": "MIT",
1985
+ "bin": {
1986
+ "jsesc": "bin/jsesc"
1987
+ },
1988
+ "engines": {
1989
+ "node": ">=6"
1990
+ }
1991
+ },
1992
+ "node_modules/json5": {
1993
+ "version": "2.2.3",
1994
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
1995
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
1996
+ "dev": true,
1997
+ "license": "MIT",
1998
+ "bin": {
1999
+ "json5": "lib/cli.js"
2000
+ },
2001
+ "engines": {
2002
+ "node": ">=6"
2003
+ }
2004
+ },
2005
+ "node_modules/lilconfig": {
2006
+ "version": "3.1.3",
2007
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
2008
+ "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
2009
+ "dev": true,
2010
+ "license": "MIT",
2011
+ "engines": {
2012
+ "node": ">=14"
2013
+ },
2014
+ "funding": {
2015
+ "url": "https://github.com/sponsors/antonk52"
2016
+ }
2017
+ },
2018
+ "node_modules/lines-and-columns": {
2019
+ "version": "1.2.4",
2020
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
2021
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
2022
+ "dev": true,
2023
+ "license": "MIT"
2024
+ },
2025
+ "node_modules/loose-envify": {
2026
+ "version": "1.4.0",
2027
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
2028
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
2029
+ "license": "MIT",
2030
+ "dependencies": {
2031
+ "js-tokens": "^3.0.0 || ^4.0.0"
2032
+ },
2033
+ "bin": {
2034
+ "loose-envify": "cli.js"
2035
+ }
2036
+ },
2037
+ "node_modules/lru-cache": {
2038
+ "version": "5.1.1",
2039
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
2040
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
2041
+ "dev": true,
2042
+ "license": "ISC",
2043
+ "dependencies": {
2044
+ "yallist": "^3.0.2"
2045
+ }
2046
+ },
2047
+ "node_modules/lucide-react": {
2048
+ "version": "0.395.0",
2049
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.395.0.tgz",
2050
+ "integrity": "sha512-6hzdNH5723A4FLaYZWpK50iyZH8iS2Jq5zuPRRotOFkhu6kxxJiebVdJ72tCR5XkiIeYFOU5NUawFZOac+VeYw==",
2051
+ "license": "ISC",
2052
+ "peerDependencies": {
2053
+ "react": "^16.5.1 || ^17.0.0 || ^18.0.0"
2054
+ }
2055
+ },
2056
+ "node_modules/math-intrinsics": {
2057
+ "version": "1.1.0",
2058
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
2059
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
2060
+ "license": "MIT",
2061
+ "engines": {
2062
+ "node": ">= 0.4"
2063
+ }
2064
+ },
2065
+ "node_modules/merge2": {
2066
+ "version": "1.4.1",
2067
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
2068
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
2069
+ "dev": true,
2070
+ "license": "MIT",
2071
+ "engines": {
2072
+ "node": ">= 8"
2073
+ }
2074
+ },
2075
+ "node_modules/micromatch": {
2076
+ "version": "4.0.8",
2077
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
2078
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
2079
+ "dev": true,
2080
+ "license": "MIT",
2081
+ "dependencies": {
2082
+ "braces": "^3.0.3",
2083
+ "picomatch": "^2.3.1"
2084
+ },
2085
+ "engines": {
2086
+ "node": ">=8.6"
2087
+ }
2088
+ },
2089
+ "node_modules/mime-db": {
2090
+ "version": "1.52.0",
2091
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
2092
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
2093
+ "license": "MIT",
2094
+ "engines": {
2095
+ "node": ">= 0.6"
2096
+ }
2097
+ },
2098
+ "node_modules/mime-types": {
2099
+ "version": "2.1.35",
2100
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
2101
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
2102
+ "license": "MIT",
2103
+ "dependencies": {
2104
+ "mime-db": "1.52.0"
2105
+ },
2106
+ "engines": {
2107
+ "node": ">= 0.6"
2108
+ }
2109
+ },
2110
+ "node_modules/ms": {
2111
+ "version": "2.1.3",
2112
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
2113
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
2114
+ "dev": true,
2115
+ "license": "MIT"
2116
+ },
2117
+ "node_modules/mz": {
2118
+ "version": "2.7.0",
2119
+ "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
2120
+ "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
2121
+ "dev": true,
2122
+ "license": "MIT",
2123
+ "dependencies": {
2124
+ "any-promise": "^1.0.0",
2125
+ "object-assign": "^4.0.1",
2126
+ "thenify-all": "^1.0.0"
2127
+ }
2128
+ },
2129
+ "node_modules/nanoid": {
2130
+ "version": "3.3.11",
2131
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
2132
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
2133
+ "dev": true,
2134
+ "funding": [
2135
+ {
2136
+ "type": "github",
2137
+ "url": "https://github.com/sponsors/ai"
2138
+ }
2139
+ ],
2140
+ "license": "MIT",
2141
+ "bin": {
2142
+ "nanoid": "bin/nanoid.cjs"
2143
+ },
2144
+ "engines": {
2145
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
2146
+ }
2147
+ },
2148
+ "node_modules/node-releases": {
2149
+ "version": "2.0.36",
2150
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz",
2151
+ "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==",
2152
+ "dev": true,
2153
+ "license": "MIT"
2154
+ },
2155
+ "node_modules/normalize-path": {
2156
+ "version": "3.0.0",
2157
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
2158
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
2159
+ "dev": true,
2160
+ "license": "MIT",
2161
+ "engines": {
2162
+ "node": ">=0.10.0"
2163
+ }
2164
+ },
2165
+ "node_modules/object-assign": {
2166
+ "version": "4.1.1",
2167
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
2168
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
2169
+ "dev": true,
2170
+ "license": "MIT",
2171
+ "engines": {
2172
+ "node": ">=0.10.0"
2173
+ }
2174
+ },
2175
+ "node_modules/object-hash": {
2176
+ "version": "3.0.0",
2177
+ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
2178
+ "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
2179
+ "dev": true,
2180
+ "license": "MIT",
2181
+ "engines": {
2182
+ "node": ">= 6"
2183
+ }
2184
+ },
2185
+ "node_modules/path-parse": {
2186
+ "version": "1.0.7",
2187
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
2188
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
2189
+ "dev": true,
2190
+ "license": "MIT"
2191
+ },
2192
+ "node_modules/picocolors": {
2193
+ "version": "1.1.1",
2194
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
2195
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
2196
+ "dev": true,
2197
+ "license": "ISC"
2198
+ },
2199
+ "node_modules/picomatch": {
2200
+ "version": "2.3.1",
2201
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
2202
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
2203
+ "dev": true,
2204
+ "license": "MIT",
2205
+ "engines": {
2206
+ "node": ">=8.6"
2207
+ },
2208
+ "funding": {
2209
+ "url": "https://github.com/sponsors/jonschlinkert"
2210
+ }
2211
+ },
2212
+ "node_modules/pify": {
2213
+ "version": "2.3.0",
2214
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
2215
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
2216
+ "dev": true,
2217
+ "license": "MIT",
2218
+ "engines": {
2219
+ "node": ">=0.10.0"
2220
+ }
2221
+ },
2222
+ "node_modules/pirates": {
2223
+ "version": "4.0.7",
2224
+ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz",
2225
+ "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==",
2226
+ "dev": true,
2227
+ "license": "MIT",
2228
+ "engines": {
2229
+ "node": ">= 6"
2230
+ }
2231
+ },
2232
+ "node_modules/postcss": {
2233
+ "version": "8.5.8",
2234
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz",
2235
+ "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==",
2236
+ "dev": true,
2237
+ "funding": [
2238
+ {
2239
+ "type": "opencollective",
2240
+ "url": "https://opencollective.com/postcss/"
2241
+ },
2242
+ {
2243
+ "type": "tidelift",
2244
+ "url": "https://tidelift.com/funding/github/npm/postcss"
2245
+ },
2246
+ {
2247
+ "type": "github",
2248
+ "url": "https://github.com/sponsors/ai"
2249
+ }
2250
+ ],
2251
+ "license": "MIT",
2252
+ "dependencies": {
2253
+ "nanoid": "^3.3.11",
2254
+ "picocolors": "^1.1.1",
2255
+ "source-map-js": "^1.2.1"
2256
+ },
2257
+ "engines": {
2258
+ "node": "^10 || ^12 || >=14"
2259
+ }
2260
+ },
2261
+ "node_modules/postcss-import": {
2262
+ "version": "15.1.0",
2263
+ "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
2264
+ "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
2265
+ "dev": true,
2266
+ "license": "MIT",
2267
+ "dependencies": {
2268
+ "postcss-value-parser": "^4.0.0",
2269
+ "read-cache": "^1.0.0",
2270
+ "resolve": "^1.1.7"
2271
+ },
2272
+ "engines": {
2273
+ "node": ">=14.0.0"
2274
+ },
2275
+ "peerDependencies": {
2276
+ "postcss": "^8.0.0"
2277
+ }
2278
+ },
2279
+ "node_modules/postcss-js": {
2280
+ "version": "4.1.0",
2281
+ "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz",
2282
+ "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==",
2283
+ "dev": true,
2284
+ "funding": [
2285
+ {
2286
+ "type": "opencollective",
2287
+ "url": "https://opencollective.com/postcss/"
2288
+ },
2289
+ {
2290
+ "type": "github",
2291
+ "url": "https://github.com/sponsors/ai"
2292
+ }
2293
+ ],
2294
+ "license": "MIT",
2295
+ "dependencies": {
2296
+ "camelcase-css": "^2.0.1"
2297
+ },
2298
+ "engines": {
2299
+ "node": "^12 || ^14 || >= 16"
2300
+ },
2301
+ "peerDependencies": {
2302
+ "postcss": "^8.4.21"
2303
+ }
2304
+ },
2305
+ "node_modules/postcss-load-config": {
2306
+ "version": "6.0.1",
2307
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz",
2308
+ "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==",
2309
+ "dev": true,
2310
+ "funding": [
2311
+ {
2312
+ "type": "opencollective",
2313
+ "url": "https://opencollective.com/postcss/"
2314
+ },
2315
+ {
2316
+ "type": "github",
2317
+ "url": "https://github.com/sponsors/ai"
2318
+ }
2319
+ ],
2320
+ "license": "MIT",
2321
+ "dependencies": {
2322
+ "lilconfig": "^3.1.1"
2323
+ },
2324
+ "engines": {
2325
+ "node": ">= 18"
2326
+ },
2327
+ "peerDependencies": {
2328
+ "jiti": ">=1.21.0",
2329
+ "postcss": ">=8.0.9",
2330
+ "tsx": "^4.8.1",
2331
+ "yaml": "^2.4.2"
2332
+ },
2333
+ "peerDependenciesMeta": {
2334
+ "jiti": {
2335
+ "optional": true
2336
+ },
2337
+ "postcss": {
2338
+ "optional": true
2339
+ },
2340
+ "tsx": {
2341
+ "optional": true
2342
+ },
2343
+ "yaml": {
2344
+ "optional": true
2345
+ }
2346
+ }
2347
+ },
2348
+ "node_modules/postcss-nested": {
2349
+ "version": "6.2.0",
2350
+ "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
2351
+ "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
2352
+ "dev": true,
2353
+ "funding": [
2354
+ {
2355
+ "type": "opencollective",
2356
+ "url": "https://opencollective.com/postcss/"
2357
+ },
2358
+ {
2359
+ "type": "github",
2360
+ "url": "https://github.com/sponsors/ai"
2361
+ }
2362
+ ],
2363
+ "license": "MIT",
2364
+ "dependencies": {
2365
+ "postcss-selector-parser": "^6.1.1"
2366
+ },
2367
+ "engines": {
2368
+ "node": ">=12.0"
2369
+ },
2370
+ "peerDependencies": {
2371
+ "postcss": "^8.2.14"
2372
+ }
2373
+ },
2374
+ "node_modules/postcss-selector-parser": {
2375
+ "version": "6.1.2",
2376
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
2377
+ "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
2378
+ "dev": true,
2379
+ "license": "MIT",
2380
+ "dependencies": {
2381
+ "cssesc": "^3.0.0",
2382
+ "util-deprecate": "^1.0.2"
2383
+ },
2384
+ "engines": {
2385
+ "node": ">=4"
2386
+ }
2387
+ },
2388
+ "node_modules/postcss-value-parser": {
2389
+ "version": "4.2.0",
2390
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
2391
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
2392
+ "dev": true,
2393
+ "license": "MIT"
2394
+ },
2395
+ "node_modules/proxy-from-env": {
2396
+ "version": "1.1.0",
2397
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
2398
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
2399
+ "license": "MIT"
2400
+ },
2401
+ "node_modules/queue-microtask": {
2402
+ "version": "1.2.3",
2403
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
2404
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
2405
+ "dev": true,
2406
+ "funding": [
2407
+ {
2408
+ "type": "github",
2409
+ "url": "https://github.com/sponsors/feross"
2410
+ },
2411
+ {
2412
+ "type": "patreon",
2413
+ "url": "https://www.patreon.com/feross"
2414
+ },
2415
+ {
2416
+ "type": "consulting",
2417
+ "url": "https://feross.org/support"
2418
+ }
2419
+ ],
2420
+ "license": "MIT"
2421
+ },
2422
+ "node_modules/react": {
2423
+ "version": "18.3.1",
2424
+ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
2425
+ "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
2426
+ "license": "MIT",
2427
+ "dependencies": {
2428
+ "loose-envify": "^1.1.0"
2429
+ },
2430
+ "engines": {
2431
+ "node": ">=0.10.0"
2432
+ }
2433
+ },
2434
+ "node_modules/react-dom": {
2435
+ "version": "18.3.1",
2436
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
2437
+ "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
2438
+ "license": "MIT",
2439
+ "dependencies": {
2440
+ "loose-envify": "^1.1.0",
2441
+ "scheduler": "^0.23.2"
2442
+ },
2443
+ "peerDependencies": {
2444
+ "react": "^18.3.1"
2445
+ }
2446
+ },
2447
+ "node_modules/react-refresh": {
2448
+ "version": "0.17.0",
2449
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
2450
+ "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
2451
+ "dev": true,
2452
+ "license": "MIT",
2453
+ "engines": {
2454
+ "node": ">=0.10.0"
2455
+ }
2456
+ },
2457
+ "node_modules/read-cache": {
2458
+ "version": "1.0.0",
2459
+ "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
2460
+ "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
2461
+ "dev": true,
2462
+ "license": "MIT",
2463
+ "dependencies": {
2464
+ "pify": "^2.3.0"
2465
+ }
2466
+ },
2467
+ "node_modules/readdirp": {
2468
+ "version": "3.6.0",
2469
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
2470
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
2471
+ "dev": true,
2472
+ "license": "MIT",
2473
+ "dependencies": {
2474
+ "picomatch": "^2.2.1"
2475
+ },
2476
+ "engines": {
2477
+ "node": ">=8.10.0"
2478
+ }
2479
+ },
2480
+ "node_modules/resolve": {
2481
+ "version": "1.22.11",
2482
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
2483
+ "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==",
2484
+ "dev": true,
2485
+ "license": "MIT",
2486
+ "dependencies": {
2487
+ "is-core-module": "^2.16.1",
2488
+ "path-parse": "^1.0.7",
2489
+ "supports-preserve-symlinks-flag": "^1.0.0"
2490
+ },
2491
+ "bin": {
2492
+ "resolve": "bin/resolve"
2493
+ },
2494
+ "engines": {
2495
+ "node": ">= 0.4"
2496
+ },
2497
+ "funding": {
2498
+ "url": "https://github.com/sponsors/ljharb"
2499
+ }
2500
+ },
2501
+ "node_modules/reusify": {
2502
+ "version": "1.1.0",
2503
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
2504
+ "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
2505
+ "dev": true,
2506
+ "license": "MIT",
2507
+ "engines": {
2508
+ "iojs": ">=1.0.0",
2509
+ "node": ">=0.10.0"
2510
+ }
2511
+ },
2512
+ "node_modules/rollup": {
2513
+ "version": "4.59.0",
2514
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz",
2515
+ "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==",
2516
+ "dev": true,
2517
+ "license": "MIT",
2518
+ "dependencies": {
2519
+ "@types/estree": "1.0.8"
2520
+ },
2521
+ "bin": {
2522
+ "rollup": "dist/bin/rollup"
2523
+ },
2524
+ "engines": {
2525
+ "node": ">=18.0.0",
2526
+ "npm": ">=8.0.0"
2527
+ },
2528
+ "optionalDependencies": {
2529
+ "@rollup/rollup-android-arm-eabi": "4.59.0",
2530
+ "@rollup/rollup-android-arm64": "4.59.0",
2531
+ "@rollup/rollup-darwin-arm64": "4.59.0",
2532
+ "@rollup/rollup-darwin-x64": "4.59.0",
2533
+ "@rollup/rollup-freebsd-arm64": "4.59.0",
2534
+ "@rollup/rollup-freebsd-x64": "4.59.0",
2535
+ "@rollup/rollup-linux-arm-gnueabihf": "4.59.0",
2536
+ "@rollup/rollup-linux-arm-musleabihf": "4.59.0",
2537
+ "@rollup/rollup-linux-arm64-gnu": "4.59.0",
2538
+ "@rollup/rollup-linux-arm64-musl": "4.59.0",
2539
+ "@rollup/rollup-linux-loong64-gnu": "4.59.0",
2540
+ "@rollup/rollup-linux-loong64-musl": "4.59.0",
2541
+ "@rollup/rollup-linux-ppc64-gnu": "4.59.0",
2542
+ "@rollup/rollup-linux-ppc64-musl": "4.59.0",
2543
+ "@rollup/rollup-linux-riscv64-gnu": "4.59.0",
2544
+ "@rollup/rollup-linux-riscv64-musl": "4.59.0",
2545
+ "@rollup/rollup-linux-s390x-gnu": "4.59.0",
2546
+ "@rollup/rollup-linux-x64-gnu": "4.59.0",
2547
+ "@rollup/rollup-linux-x64-musl": "4.59.0",
2548
+ "@rollup/rollup-openbsd-x64": "4.59.0",
2549
+ "@rollup/rollup-openharmony-arm64": "4.59.0",
2550
+ "@rollup/rollup-win32-arm64-msvc": "4.59.0",
2551
+ "@rollup/rollup-win32-ia32-msvc": "4.59.0",
2552
+ "@rollup/rollup-win32-x64-gnu": "4.59.0",
2553
+ "@rollup/rollup-win32-x64-msvc": "4.59.0",
2554
+ "fsevents": "~2.3.2"
2555
+ }
2556
+ },
2557
+ "node_modules/run-parallel": {
2558
+ "version": "1.2.0",
2559
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
2560
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
2561
+ "dev": true,
2562
+ "funding": [
2563
+ {
2564
+ "type": "github",
2565
+ "url": "https://github.com/sponsors/feross"
2566
+ },
2567
+ {
2568
+ "type": "patreon",
2569
+ "url": "https://www.patreon.com/feross"
2570
+ },
2571
+ {
2572
+ "type": "consulting",
2573
+ "url": "https://feross.org/support"
2574
+ }
2575
+ ],
2576
+ "license": "MIT",
2577
+ "dependencies": {
2578
+ "queue-microtask": "^1.2.2"
2579
+ }
2580
+ },
2581
+ "node_modules/scheduler": {
2582
+ "version": "0.23.2",
2583
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
2584
+ "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
2585
+ "license": "MIT",
2586
+ "dependencies": {
2587
+ "loose-envify": "^1.1.0"
2588
+ }
2589
+ },
2590
+ "node_modules/semver": {
2591
+ "version": "6.3.1",
2592
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
2593
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
2594
+ "dev": true,
2595
+ "license": "ISC",
2596
+ "bin": {
2597
+ "semver": "bin/semver.js"
2598
+ }
2599
+ },
2600
+ "node_modules/source-map-js": {
2601
+ "version": "1.2.1",
2602
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
2603
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
2604
+ "dev": true,
2605
+ "license": "BSD-3-Clause",
2606
+ "engines": {
2607
+ "node": ">=0.10.0"
2608
+ }
2609
+ },
2610
+ "node_modules/sucrase": {
2611
+ "version": "3.35.1",
2612
+ "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz",
2613
+ "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==",
2614
+ "dev": true,
2615
+ "license": "MIT",
2616
+ "dependencies": {
2617
+ "@jridgewell/gen-mapping": "^0.3.2",
2618
+ "commander": "^4.0.0",
2619
+ "lines-and-columns": "^1.1.6",
2620
+ "mz": "^2.7.0",
2621
+ "pirates": "^4.0.1",
2622
+ "tinyglobby": "^0.2.11",
2623
+ "ts-interface-checker": "^0.1.9"
2624
+ },
2625
+ "bin": {
2626
+ "sucrase": "bin/sucrase",
2627
+ "sucrase-node": "bin/sucrase-node"
2628
+ },
2629
+ "engines": {
2630
+ "node": ">=16 || 14 >=14.17"
2631
+ }
2632
+ },
2633
+ "node_modules/supports-preserve-symlinks-flag": {
2634
+ "version": "1.0.0",
2635
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
2636
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
2637
+ "dev": true,
2638
+ "license": "MIT",
2639
+ "engines": {
2640
+ "node": ">= 0.4"
2641
+ },
2642
+ "funding": {
2643
+ "url": "https://github.com/sponsors/ljharb"
2644
+ }
2645
+ },
2646
+ "node_modules/tailwindcss": {
2647
+ "version": "3.4.19",
2648
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz",
2649
+ "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==",
2650
+ "dev": true,
2651
+ "license": "MIT",
2652
+ "dependencies": {
2653
+ "@alloc/quick-lru": "^5.2.0",
2654
+ "arg": "^5.0.2",
2655
+ "chokidar": "^3.6.0",
2656
+ "didyoumean": "^1.2.2",
2657
+ "dlv": "^1.1.3",
2658
+ "fast-glob": "^3.3.2",
2659
+ "glob-parent": "^6.0.2",
2660
+ "is-glob": "^4.0.3",
2661
+ "jiti": "^1.21.7",
2662
+ "lilconfig": "^3.1.3",
2663
+ "micromatch": "^4.0.8",
2664
+ "normalize-path": "^3.0.0",
2665
+ "object-hash": "^3.0.0",
2666
+ "picocolors": "^1.1.1",
2667
+ "postcss": "^8.4.47",
2668
+ "postcss-import": "^15.1.0",
2669
+ "postcss-js": "^4.0.1",
2670
+ "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0",
2671
+ "postcss-nested": "^6.2.0",
2672
+ "postcss-selector-parser": "^6.1.2",
2673
+ "resolve": "^1.22.8",
2674
+ "sucrase": "^3.35.0"
2675
+ },
2676
+ "bin": {
2677
+ "tailwind": "lib/cli.js",
2678
+ "tailwindcss": "lib/cli.js"
2679
+ },
2680
+ "engines": {
2681
+ "node": ">=14.0.0"
2682
+ }
2683
+ },
2684
+ "node_modules/thenify": {
2685
+ "version": "3.3.1",
2686
+ "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
2687
+ "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
2688
+ "dev": true,
2689
+ "license": "MIT",
2690
+ "dependencies": {
2691
+ "any-promise": "^1.0.0"
2692
+ }
2693
+ },
2694
+ "node_modules/thenify-all": {
2695
+ "version": "1.6.0",
2696
+ "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
2697
+ "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
2698
+ "dev": true,
2699
+ "license": "MIT",
2700
+ "dependencies": {
2701
+ "thenify": ">= 3.1.0 < 4"
2702
+ },
2703
+ "engines": {
2704
+ "node": ">=0.8"
2705
+ }
2706
+ },
2707
+ "node_modules/tinyglobby": {
2708
+ "version": "0.2.15",
2709
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
2710
+ "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
2711
+ "dev": true,
2712
+ "license": "MIT",
2713
+ "dependencies": {
2714
+ "fdir": "^6.5.0",
2715
+ "picomatch": "^4.0.3"
2716
+ },
2717
+ "engines": {
2718
+ "node": ">=12.0.0"
2719
+ },
2720
+ "funding": {
2721
+ "url": "https://github.com/sponsors/SuperchupuDev"
2722
+ }
2723
+ },
2724
+ "node_modules/tinyglobby/node_modules/fdir": {
2725
+ "version": "6.5.0",
2726
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
2727
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
2728
+ "dev": true,
2729
+ "license": "MIT",
2730
+ "engines": {
2731
+ "node": ">=12.0.0"
2732
+ },
2733
+ "peerDependencies": {
2734
+ "picomatch": "^3 || ^4"
2735
+ },
2736
+ "peerDependenciesMeta": {
2737
+ "picomatch": {
2738
+ "optional": true
2739
+ }
2740
+ }
2741
+ },
2742
+ "node_modules/tinyglobby/node_modules/picomatch": {
2743
+ "version": "4.0.3",
2744
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
2745
+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
2746
+ "dev": true,
2747
+ "license": "MIT",
2748
+ "engines": {
2749
+ "node": ">=12"
2750
+ },
2751
+ "funding": {
2752
+ "url": "https://github.com/sponsors/jonschlinkert"
2753
+ }
2754
+ },
2755
+ "node_modules/to-regex-range": {
2756
+ "version": "5.0.1",
2757
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
2758
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
2759
+ "dev": true,
2760
+ "license": "MIT",
2761
+ "dependencies": {
2762
+ "is-number": "^7.0.0"
2763
+ },
2764
+ "engines": {
2765
+ "node": ">=8.0"
2766
+ }
2767
+ },
2768
+ "node_modules/ts-interface-checker": {
2769
+ "version": "0.1.13",
2770
+ "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
2771
+ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
2772
+ "dev": true,
2773
+ "license": "Apache-2.0"
2774
+ },
2775
+ "node_modules/update-browserslist-db": {
2776
+ "version": "1.2.3",
2777
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
2778
+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
2779
+ "dev": true,
2780
+ "funding": [
2781
+ {
2782
+ "type": "opencollective",
2783
+ "url": "https://opencollective.com/browserslist"
2784
+ },
2785
+ {
2786
+ "type": "tidelift",
2787
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
2788
+ },
2789
+ {
2790
+ "type": "github",
2791
+ "url": "https://github.com/sponsors/ai"
2792
+ }
2793
+ ],
2794
+ "license": "MIT",
2795
+ "dependencies": {
2796
+ "escalade": "^3.2.0",
2797
+ "picocolors": "^1.1.1"
2798
+ },
2799
+ "bin": {
2800
+ "update-browserslist-db": "cli.js"
2801
+ },
2802
+ "peerDependencies": {
2803
+ "browserslist": ">= 4.21.0"
2804
+ }
2805
+ },
2806
+ "node_modules/util-deprecate": {
2807
+ "version": "1.0.2",
2808
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
2809
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
2810
+ "dev": true,
2811
+ "license": "MIT"
2812
+ },
2813
+ "node_modules/vite": {
2814
+ "version": "5.4.21",
2815
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz",
2816
+ "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
2817
+ "dev": true,
2818
+ "license": "MIT",
2819
+ "dependencies": {
2820
+ "esbuild": "^0.21.3",
2821
+ "postcss": "^8.4.43",
2822
+ "rollup": "^4.20.0"
2823
+ },
2824
+ "bin": {
2825
+ "vite": "bin/vite.js"
2826
+ },
2827
+ "engines": {
2828
+ "node": "^18.0.0 || >=20.0.0"
2829
+ },
2830
+ "funding": {
2831
+ "url": "https://github.com/vitejs/vite?sponsor=1"
2832
+ },
2833
+ "optionalDependencies": {
2834
+ "fsevents": "~2.3.3"
2835
+ },
2836
+ "peerDependencies": {
2837
+ "@types/node": "^18.0.0 || >=20.0.0",
2838
+ "less": "*",
2839
+ "lightningcss": "^1.21.0",
2840
+ "sass": "*",
2841
+ "sass-embedded": "*",
2842
+ "stylus": "*",
2843
+ "sugarss": "*",
2844
+ "terser": "^5.4.0"
2845
+ },
2846
+ "peerDependenciesMeta": {
2847
+ "@types/node": {
2848
+ "optional": true
2849
+ },
2850
+ "less": {
2851
+ "optional": true
2852
+ },
2853
+ "lightningcss": {
2854
+ "optional": true
2855
+ },
2856
+ "sass": {
2857
+ "optional": true
2858
+ },
2859
+ "sass-embedded": {
2860
+ "optional": true
2861
+ },
2862
+ "stylus": {
2863
+ "optional": true
2864
+ },
2865
+ "sugarss": {
2866
+ "optional": true
2867
+ },
2868
+ "terser": {
2869
+ "optional": true
2870
+ }
2871
+ }
2872
+ },
2873
+ "node_modules/yallist": {
2874
+ "version": "3.1.1",
2875
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
2876
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
2877
+ "dev": true,
2878
+ "license": "ISC"
2879
+ }
2880
+ }
2881
+ }
frontend/package.json ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "traffic-incident-summarization-frontend",
3
+ "private": true,
4
+ "version": "0.1.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "vite build",
9
+ "preview": "vite preview"
10
+ },
11
+ "dependencies": {
12
+ "axios": "^1.7.2",
13
+ "lucide-react": "^0.395.0",
14
+ "react": "^18.3.1",
15
+ "react-dom": "^18.3.1"
16
+ },
17
+ "devDependencies": {
18
+ "@vitejs/plugin-react": "^4.3.1",
19
+ "autoprefixer": "^10.4.19",
20
+ "postcss": "^8.4.38",
21
+ "tailwindcss": "^3.4.4",
22
+ "vite": "^5.2.12"
23
+ }
24
+ }
frontend/postcss.config.js ADDED
@@ -0,0 +1 @@
 
 
1
+ export default { plugins: { tailwindcss: {}, autoprefixer: {} } };
frontend/src/App.jsx ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ import Home from "./pages/Home";
2
+ export default function App() { return <Home />; }
frontend/src/api/client.js ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import axios from "axios";
2
+
3
+ const api = axios.create({
4
+ baseURL: "http://127.0.0.1:8000"
5
+ });
6
+
7
+ export async function summarizeText(payload) {
8
+ const { data } = await api.post("/summarize", payload);
9
+ return data;
10
+ }
11
+
12
+ export async function compareModels(payload) {
13
+ const { data } = await api.post("/compare", payload);
14
+ return data;
15
+ }
16
+
17
+ export async function fetchSamples(track) {
18
+ const { data } = await api.get(`/samples?track=${track}`);
19
+ return data.items || [];
20
+ }
frontend/src/components/BatchUpload.jsx ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { UploadCloud } from "lucide-react";
2
+
3
+ export default function BatchUpload() {
4
+ return (
5
+ <div className="rounded-[24px] border border-slate-200 bg-white p-6 shadow-sm dark:border-slate-800 dark:bg-[#0d1326] dark:shadow-xl relative overflow-hidden h-full">
6
+ <div className="mb-2 text-xs font-semibold uppercase tracking-[0.18em] text-orange-600 dark:text-orange-400">Batch Processing</div>
7
+ <h3 className="text-xl font-bold text-slate-900 dark:text-white mt-1">Bulk Generation</h3>
8
+ <p className="mt-3 text-sm leading-relaxed text-slate-600 dark:text-slate-400">
9
+ Load custom evaluation datasets by uploading a CSV. The system expects a <span className="font-mono text-xs text-orange-600 bg-orange-50 px-1 py-0.5 rounded dark:text-orange-300 dark:bg-orange-500/10 dark:border dark:border-orange-500/20">Description</span> column to generate summaries in bulk for evaluation.
10
+ </p>
11
+
12
+ <div className="mt-6 flex flex-col items-center justify-center rounded-[20px] border-2 border-dashed border-slate-200 bg-slate-50 p-8 text-center transition hover:border-orange-200 hover:bg-orange-50 cursor-pointer group dark:border-slate-700 dark:bg-slate-900/50 dark:hover:border-orange-500/50 dark:hover:bg-slate-800">
13
+ <div className="rounded-full bg-white border border-slate-200 p-3 text-slate-400 mb-3 group-hover:text-orange-500 group-hover:bg-orange-100 group-hover:border-orange-200 transition-colors dark:bg-slate-800 dark:border-slate-700 dark:group-hover:text-orange-400 dark:group-hover:bg-orange-500/10 dark:group-hover:border-orange-500/30">
14
+ <UploadCloud size={24} />
15
+ </div>
16
+ <div className="text-sm font-bold text-slate-700 group-hover:text-orange-600 mb-1 dark:text-slate-300 dark:group-hover:text-white">Upload CSV or JSON Dataset</div>
17
+ <div className="text-xs text-slate-500">Supports .csv up to 50MB</div>
18
+ </div>
19
+ </div>
20
+ );
21
+ }
frontend/src/components/CompareGrid.jsx ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export default function CompareGrid({ items }) {
2
+ if (!items?.length) {
3
+ return (
4
+ <div className="rounded-[28px] border border-dashed border-slate-200 bg-slate-50 p-8 text-sm text-slate-500 dark:border-slate-800 dark:bg-[#121930] dark:text-slate-400">
5
+ Compare all models to render side-by-side summaries for qualitative analysis.
6
+ </div>
7
+ );
8
+ }
9
+
10
+ return (
11
+ <div className="grid gap-4 lg:grid-cols-2 xl:grid-cols-3">
12
+ {items.map((item) => (
13
+ <div key={item.model_name} className="rounded-[28px] border border-slate-200 bg-white p-5 shadow-sm dark:border-slate-800 dark:bg-[#121930] dark:shadow-md">
14
+ <div className="mb-4 flex items-center justify-between gap-3">
15
+ <div className="text-sm font-bold text-slate-900 dark:text-white">{item.model_name}</div>
16
+ <div className="rounded-full bg-slate-100 px-3 py-1 text-[11px] font-bold uppercase tracking-[0.15em] text-slate-600 dark:bg-slate-800 dark:text-slate-400">
17
+ {item.word_count || item.summary?.split(/\s+/).filter(Boolean).length || 0} words
18
+ </div>
19
+ </div>
20
+ <p className="text-sm leading-8 text-slate-600 dark:text-slate-300">{item.summary}</p>
21
+ </div>
22
+ ))}
23
+ </div>
24
+ );
25
+ }
frontend/src/components/DatasetToggle.jsx ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Check, Database } from "lucide-react";
2
+
3
+ export default function DatasetToggle({ value, onChange }) {
4
+ const options = [
5
+ { value: "gcc", label: "GCC / UAE", subtitle: "250+ Narrative Samples" },
6
+ { value: "us", label: "US Accidents", subtitle: "5,000+ Extracted Records" }
7
+ ];
8
+
9
+ return (
10
+ <div className="rounded-[24px] border border-slate-200 bg-white p-6 shadow-sm dark:border-slate-800 dark:bg-slate-900/50 dark:shadow-xl backdrop-blur">
11
+ <div className="flex items-center gap-2 mb-4 text-xs font-bold uppercase tracking-[0.2em] text-slate-500 dark:text-slate-400">
12
+ <Database size={14}/> Analysis Dataset Track
13
+ </div>
14
+ <div className="grid gap-4 sm:grid-cols-2">
15
+ {options.map((option) => {
16
+ const isSelected = value === option.value;
17
+ return (
18
+ <button
19
+ key={option.value}
20
+ type="button"
21
+ onClick={() => onChange(option.value)}
22
+ className={`relative flex flex-col items-start rounded-2xl border-2 px-5 py-4 text-left transition-all duration-300 ${
23
+ isSelected
24
+ ? "border-orange-500 bg-orange-50/50 shadow-[0_0_15px_rgba(249,115,22,0.15)] ring-1 ring-orange-500/50 dark:bg-orange-500/10"
25
+ : "border-slate-200 bg-slate-50 hover:border-slate-300 hover:bg-slate-100 dark:border-slate-800 dark:bg-slate-800/40 dark:hover:border-slate-700 dark:hover:bg-slate-800/80"
26
+ }`}
27
+ >
28
+ <div className="flex w-full items-center justify-between">
29
+ <span className={`text-lg font-bold ${isSelected ? "text-orange-600 dark:text-orange-400" : "text-slate-700 dark:text-slate-300"}`}>
30
+ {option.label}
31
+ </span>
32
+ <div className={`flex h-6 w-6 items-center justify-center rounded-full transition-transform duration-300 ${isSelected ? "scale-100 bg-orange-500 text-white dark:text-slate-900" : "scale-0 shadow-none border-0"}`}>
33
+ <Check size={14} strokeWidth={3} />
34
+ </div>
35
+ </div>
36
+ <span className={`mt-2 text-xs font-medium uppercase tracking-widest ${isSelected ? "text-orange-600/80 dark:text-orange-400/80" : "text-slate-500"}`}>
37
+ {option.subtitle}
38
+ </span>
39
+ </button>
40
+ );
41
+ })}
42
+ </div>
43
+ </div>
44
+ );
45
+ }
frontend/src/components/LengthSlider.jsx ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export default function LengthSlider({ value, onChange }) {
2
+ return (
3
+ <div className="space-y-4 rounded-3xl border border-white/60 bg-white/70 p-4 shadow-sm backdrop-blur">
4
+ <div className="flex items-center justify-between">
5
+ <label className="block text-xs font-semibold uppercase tracking-[0.18em] text-slate-400">Max summary length</label>
6
+ <span className="rounded-full bg-indigo-50 px-3 py-1 text-xs font-bold text-indigo-700 shadow-sm">
7
+ {value} tokens
8
+ </span>
9
+ </div>
10
+ <input
11
+ type="range"
12
+ min="20"
13
+ max="256"
14
+ step="4"
15
+ value={value}
16
+ onChange={(e) => onChange(Number(e.target.value))}
17
+ className="h-2 w-full appearance-none rounded-lg bg-slate-200 accent-indigo-500 hover:accent-indigo-600 focus:outline-none focus:ring-2 focus:ring-indigo-500/50"
18
+ />
19
+ <div className="flex justify-between px-1 text-[10px] font-bold uppercase tracking-widest text-slate-400">
20
+ <span>Short base</span>
21
+ <span>Detailed report</span>
22
+ </div>
23
+ </div>
24
+ );
25
+ }
frontend/src/components/ModelSelector.jsx ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const OPTIONS = [
2
+ { value: "bart_large_cnn", label: "BART Large CNN", note: "Best default abstractive model" },
3
+ { value: "flan_t5_small", label: "Flan-T5 Small", note: "Lightweight and CPU-friendly" },
4
+ { value: "pegasus_cnn", label: "PEGASUS CNN", note: "Optional stronger summarizer" },
5
+ { value: "lead1", label: "Lead-1", note: "Simple extractive baseline" },
6
+ { value: "textrank", label: "TextRank", note: "Classic graph-based baseline" }
7
+ ];
8
+
9
+ export default function ModelSelector({ value, onChange }) {
10
+ const selected = OPTIONS.find((option) => option.value === value);
11
+
12
+ return (
13
+ <div className="space-y-3 rounded-3xl border border-white/60 bg-white/70 p-4 shadow-sm backdrop-blur">
14
+ <label className="block text-xs font-semibold uppercase tracking-[0.18em] text-slate-400">Summarization Model</label>
15
+ <select
16
+ className="w-full appearance-none rounded-2xl border-none bg-white p-4 text-sm font-semibold text-slate-800 shadow-sm outline-none transition-all focus:ring-4 focus:ring-sky-500/20"
17
+ value={value}
18
+ onChange={(e) => onChange(e.target.value)}
19
+ >
20
+ {OPTIONS.map((option) => (
21
+ <option key={option.value} value={option.value}>{option.label}</option>
22
+ ))}
23
+ </select>
24
+ {selected && (
25
+ <p className="px-1 text-xs font-medium text-slate-500">{selected.note}</p>
26
+ )}
27
+ </div>
28
+ );
29
+ }
30
+
31
+ export const MODEL_OPTIONS = OPTIONS;
frontend/src/components/SampleGallery.jsx ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function getSeverityBadge(text) {
2
+ const match = text.match(/(critical|high|medium|low)\sseverity/i);
3
+ if (!match) return null;
4
+ const sev = match[1].toUpperCase();
5
+ switch (sev) {
6
+ case 'CRITICAL': return <div className="mt-4 inline-flex items-center rounded-full border border-red-500/30 bg-red-500/10 px-2.5 py-0.5 text-[10px] font-bold uppercase tracking-wider text-red-500 dark:text-red-400">Critical Severity</div>;
7
+ case 'HIGH': return <div className="mt-4 inline-flex items-center rounded-full border border-orange-500/30 bg-orange-500/10 px-2.5 py-0.5 text-[10px] font-bold uppercase tracking-wider text-orange-600 dark:text-orange-400">High Severity</div>;
8
+ case 'MEDIUM': return <div className="mt-4 inline-flex items-center rounded-full border border-yellow-500/30 bg-yellow-500/10 px-2.5 py-0.5 text-[10px] font-bold uppercase tracking-wider text-yellow-600 dark:text-yellow-400">Medium Severity</div>;
9
+ case 'LOW': return <div className="mt-4 inline-flex items-center rounded-full border border-emerald-500/30 bg-emerald-500/10 px-2.5 py-0.5 text-[10px] font-bold uppercase tracking-wider text-emerald-600 dark:text-emerald-400">Low Severity</div>;
10
+ default: return null;
11
+ }
12
+ }
13
+
14
+ export default function SampleGallery({ items, onPick }) {
15
+ if (!items?.length) {
16
+ return (
17
+ <div className="rounded-3xl border border-dashed border-slate-200 bg-slate-50 p-6 text-sm text-slate-500 dark:border-slate-800 dark:bg-[#121930]">
18
+ No sample incidents available for this dataset track yet.
19
+ </div>
20
+ );
21
+ }
22
+
23
+ return (
24
+ <div className="flex flex-col gap-4 w-full pr-2">
25
+ {items.map((item) => (
26
+ <button
27
+ key={`${item.dataset_track}-${item.id}`}
28
+ onClick={() => onPick(item.text)}
29
+ className="group rounded-2xl border border-slate-200 bg-white p-5 text-left shadow-sm transition hover:border-slate-300 hover:bg-slate-50 dark:border-slate-800 dark:bg-[#121930] dark:hover:border-slate-700 dark:hover:bg-slate-800/80 w-full"
30
+ >
31
+ <div className="mb-3 flex items-center justify-between gap-4">
32
+ <div className="text-xs font-semibold uppercase tracking-[0.18em] text-orange-600 dark:text-orange-500">{item.dataset_track}</div>
33
+ <div className="rounded-full bg-slate-100 border border-slate-200 px-3 py-1 text-[11px] font-medium text-slate-600 dark:bg-slate-800 dark:border-slate-700 dark:text-slate-400">{item.source_label}</div>
34
+ </div>
35
+ <div className="mb-2 text-base font-bold text-slate-900 group-hover:text-orange-600 dark:text-white dark:group-hover:text-orange-400">{item.title}</div>
36
+ <p className="line-clamp-2 text-sm leading-7 text-slate-600 dark:text-slate-400">{item.text}</p>
37
+ {getSeverityBadge(item.text)}
38
+ </button>
39
+ ))}
40
+ </div>
41
+ );
42
+ }
frontend/src/components/SummarizerWidget.jsx ADDED
@@ -0,0 +1,310 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useState, useMemo } from "react";
2
+ import { Copy, UploadCloud, FileText, Zap, Cpu, Sun, Layers, ArrowRight, Download, CheckCircle2 } from "lucide-react";
3
+
4
+ export const MODELS = [
5
+ {
6
+ id: "bart_large_cnn",
7
+ name: "BART",
8
+ badgeLabel: "Top Pick",
9
+ badgeColor: "text-orange-600 bg-orange-100 border-orange-200 dark:text-orange-400 dark:border-orange-500/30 dark:bg-orange-500/10",
10
+ speed: 2,
11
+ icon: Cpu,
12
+ description: "Meta's BART model fine-tuned on CNN/DailyMail. It produces highly abstractive, narrative-style summaries, making it the best overall for rewriting raw incident descriptions into fluent reports."
13
+ },
14
+ {
15
+ id: "flan_t5_small",
16
+ name: "Flan-T5",
17
+ badgeLabel: "Fast",
18
+ badgeColor: "text-blue-600 bg-blue-100 border-blue-200 dark:text-blue-400 dark:border-blue-500/30 dark:bg-blue-500/10",
19
+ speed: 3,
20
+ icon: Zap,
21
+ description: "Google's instruction-tuned T5 model. It's incredibly fast and lightweight to run locally on CPU, though its summaries can occasionally be more concise and rigid than BART."
22
+ },
23
+ {
24
+ id: "pegasus_cnn",
25
+ name: "PEGASUS",
26
+ badgeLabel: "Precise",
27
+ badgeColor: "text-emerald-600 bg-emerald-100 border-emerald-200 dark:text-emerald-400 dark:border-emerald-500/30 dark:bg-emerald-500/10",
28
+ speed: 1,
29
+ icon: Layers,
30
+ description: "Google's PEGASUS model designed specifically for summarization. It is highly precise but computationally heavy, resulting in slower generation times."
31
+ },
32
+ {
33
+ id: "textrank",
34
+ name: "TextRank",
35
+ badgeLabel: "Offline",
36
+ badgeColor: "text-purple-600 bg-purple-100 border-purple-200 dark:text-purple-400 dark:border-purple-500/30 dark:bg-purple-500/10",
37
+ speed: 3,
38
+ icon: Sun,
39
+ description: "A classic non-neural extractive model based on PageRank. It works entirely offline without a GPU by identifying and extracting the most important exact sentences from the text."
40
+ }
41
+ ];
42
+
43
+ function downloadTextFile(filename, content) {
44
+ const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
45
+ const url = URL.createObjectURL(blob);
46
+ const link = document.createElement("a");
47
+ link.href = url;
48
+ link.download = filename;
49
+ document.body.appendChild(link);
50
+ link.click();
51
+ link.remove();
52
+ URL.revokeObjectURL(url);
53
+ }
54
+
55
+ function extractTags(text) {
56
+ if (!text) return [];
57
+ try {
58
+ const tags = [];
59
+
60
+ // Vehicles
61
+ const vehicleMatch = text.match(/\b(\d+|two|three|four|five|several|multiple)\s+(?:vehicles?|cars?|trucks?)\b/i);
62
+ if (vehicleMatch) tags.push(vehicleMatch[1].toLowerCase() + " vehicles");
63
+
64
+ // Duration (minutes)
65
+ const minMatch = text.match(/\b(\d+)\s*(?:min|minutes?)\b/i);
66
+ if (minMatch) tags.push(minMatch[1] + " min");
67
+
68
+ // Distance (miles/km)
69
+ const miMatch = text.match(/\b(\d+(?:\.\d+)?)\s*(?:miles?|mi|km)\b/i);
70
+ if (miMatch) tags.push(miMatch[1] + " mi backup");
71
+
72
+ // Road codes like D71, E11
73
+ const codeMatches = text.match(/\b[A-Z]\d{1,3}\b/g);
74
+ if (codeMatches) {
75
+ codeMatches.forEach(c => { if (!tags.includes(c)) tags.push(c); });
76
+ }
77
+
78
+ // Named roads (safe version)
79
+ const roadMatch = text.match(/\b(?:Sheikh\s+Zayed|Hessa|Al\s+Khail|E[0-9]+|Highway\s+\d+|I-\d+|Route\s+\d+)[^,.]*(?:Road|Rd|Street|St|Hwy)?\b/gi);
80
+ if (roadMatch) {
81
+ const shortRoad = roadMatch[0].trim().split(' ').slice(0, 3).join(' ');
82
+ if (!tags.some(t => t.toLowerCase() === shortRoad.toLowerCase())) tags.push(shortRoad);
83
+ }
84
+
85
+ return Array.from(new Set(tags)).slice(0, 4);
86
+ } catch (_) {
87
+ return [];
88
+ }
89
+ }
90
+
91
+ export default function SummarizerWidget({
92
+ text,
93
+ setText,
94
+ maxLength,
95
+ setMaxLength,
96
+ modelChoice,
97
+ setModelChoice,
98
+ onSummarize,
99
+ loading,
100
+ summary
101
+ }) {
102
+ const wordCount = text.trim() ? text.trim().split(/\s+/).length : 0;
103
+ const summaryWordCount = summary ? summary.split(/\s+/).filter(Boolean).length : 0;
104
+
105
+ const [copied, setCopied] = useState(false);
106
+
107
+ const extractedTags = useMemo(() => {
108
+ return summary ? extractTags(summary + " " + text) : [];
109
+ // eslint-disable-next-line react-hooks/exhaustive-deps
110
+ }, [summary]);
111
+
112
+ const handleCopy = () => {
113
+ if (!summary) return;
114
+ navigator.clipboard.writeText(summary);
115
+ setCopied(true);
116
+ setTimeout(() => setCopied(false), 2000);
117
+ };
118
+
119
+ return (
120
+ <div className="w-full">
121
+ <div className="mb-6 space-y-4">
122
+ <span className="inline-flex items-center gap-2 rounded-full border border-orange-200 bg-orange-50 px-4 py-1.5 text-xs font-semibold uppercase tracking-widest text-orange-600 dark:border-orange-500/40 dark:bg-orange-500/10 dark:text-orange-400">
123
+ <span className="h-1.5 w-1.5 rounded-full bg-orange-500"></span> AI-powered traffic intelligence
124
+ </span>
125
+ <h1 className="text-4xl md:text-5xl font-black tracking-tight text-slate-900 dark:text-white leading-tight">
126
+ Turn Traffic Chaos <br /> <span className="text-transparent bg-clip-text bg-gradient-to-r from-orange-500 to-orange-600 dark:from-orange-400 dark:to-orange-500">into Clarity</span>
127
+ </h1>
128
+ <p className="text-sm md:text-base text-slate-600 dark:text-slate-400 max-w-2xl font-medium">
129
+ Paste raw incident reports and instantly get AI-distilled summaries from state-of-the-art models. Check the split-view output above.
130
+ </p>
131
+ </div>
132
+
133
+ <div className="rounded-[24px] border border-slate-200 bg-white/70 shadow-2xl backdrop-blur-xl dark:border-slate-800 dark:bg-[#0d1326]/60">
134
+
135
+ {/* Input and Output Split Area */}
136
+ <div className="grid gap-0 lg:grid-cols-2">
137
+ {/* LEFT PANE: INPUT */}
138
+ <div className="p-6 md:p-8 flex flex-col relative">
139
+ <div className="flex items-center justify-between border-b border-slate-200 pb-3 mb-4 dark:border-slate-800">
140
+ <h3 className="text-xs font-bold uppercase tracking-[0.2em] text-slate-500 dark:text-slate-400">Original Incident</h3>
141
+ <span className="rounded-full bg-slate-100 px-3 py-1 text-[11px] font-bold text-slate-600 dark:bg-slate-800/80 dark:text-slate-400">
142
+ {wordCount} words
143
+ </span>
144
+ </div>
145
+ <textarea
146
+ className="w-full flex-1 min-h-[360px] resize-y rounded-2xl bg-transparent p-0 text-base leading-relaxed text-slate-700 placeholder:text-slate-400 focus:outline-none focus:ring-0 dark:text-slate-200 dark:placeholder:text-slate-600"
147
+ placeholder="Paste a traffic incident report here, or click an example below..."
148
+ value={text}
149
+ onChange={(e) => setText(e.target.value)}
150
+ />
151
+ <div className="mt-4 pt-4 border-t border-slate-200 border-dashed dark:border-slate-800">
152
+ <button
153
+ className="flex items-center gap-2 text-xs font-bold uppercase tracking-wider text-slate-400 hover:text-slate-600 dark:text-slate-500 dark:hover:text-slate-300 transition-colors"
154
+ onClick={() => setText("")}
155
+ >
156
+ Clear Text
157
+ </button>
158
+ </div>
159
+ </div>
160
+
161
+ {/* RIGHT PANE: OUTPUT */}
162
+ <div className="p-6 md:p-8 flex flex-col relative border-t lg:border-t-0 lg:border-l border-slate-200 dark:border-slate-800 bg-slate-50/50 dark:bg-[#121930]/40 rounded-b-[24px] lg:rounded-bl-none lg:rounded-tr-[24px]">
163
+ <div className="flex items-center justify-between border-b border-orange-200/50 pb-3 mb-4 dark:border-slate-800">
164
+ <h3 className="text-xs font-bold uppercase tracking-[0.2em] text-orange-600 dark:text-orange-400">Generated Model Output • {modelChoice}</h3>
165
+ {summary ? (
166
+ <span className="flex h-6 w-6 items-center justify-center rounded-full bg-orange-100 text-[10px] font-bold text-orange-600 dark:bg-orange-500/20 dark:text-orange-400">
167
+ {summaryWordCount}
168
+ </span>
169
+ ) : null}
170
+ </div>
171
+ <div className="flex-1 overflow-auto min-h-[320px] flex flex-col">
172
+ {summary ? (
173
+ <>
174
+ <p className="text-base leading-relaxed text-slate-800 dark:text-slate-200 whitespace-pre-wrap flex-1">{summary.replace(/<n>/gi, '\n\n').replace(/[ \t]+/g, ' ').trim()}</p>
175
+ {extractedTags.length > 0 && (
176
+ <div className="mt-4 flex flex-wrap gap-2 pt-2">
177
+ {extractedTags.map((tag, idx) => (
178
+ <span key={idx} className="inline-flex items-center rounded-full border border-orange-500/20 bg-orange-500/5 px-4 py-1.5 text-[11px] font-bold text-orange-600 dark:border-orange-500/30 dark:bg-[#1a0f0d] dark:text-orange-400 capitalize tracking-wide shadow-sm">
179
+ {tag}
180
+ </span>
181
+ ))}
182
+ </div>
183
+ )}
184
+ </>
185
+ ) : (
186
+ <div className="h-full flex-1 flex items-center justify-center text-sm font-medium text-slate-400 dark:text-slate-500 italic">
187
+ {loading ? "Generating summary..." : "No summary generated yet."}
188
+ </div>
189
+ )}
190
+ </div>
191
+ {summary && (
192
+ <div className="mt-6 flex flex-wrap gap-3 border-t border-slate-200/50 dark:border-slate-800/50 pt-4">
193
+ <button
194
+ onClick={handleCopy}
195
+ className="flex-1 flex justify-center items-center gap-2 rounded-xl bg-slate-900 py-3 text-sm font-bold text-white transition hover:bg-slate-800 dark:bg-slate-800 dark:hover:bg-slate-700"
196
+ >
197
+ {copied ? <CheckCircle2 size={16}/> : <Copy size={16} />} {copied ? "Copied" : "Copy"}
198
+ </button>
199
+ <button
200
+ onClick={() => downloadTextFile(`summary_${modelChoice}.txt`, summary)}
201
+ className="flex-1 flex justify-center items-center gap-2 rounded-xl border border-slate-300 bg-white py-3 text-sm font-bold text-slate-700 transition hover:bg-slate-50 dark:border-slate-700 dark:bg-[#121930] dark:text-slate-300 dark:hover:bg-slate-800"
202
+ >
203
+ <Download size={16} /> Save
204
+ </button>
205
+ </div>
206
+ )}
207
+ </div>
208
+ </div>
209
+
210
+ {/* Separator */}
211
+ <div className="h-px w-full bg-slate-200 dark:bg-slate-800"></div>
212
+
213
+ {/* Controls block */}
214
+ <div className="p-6 md:p-8 space-y-8">
215
+ {/* Model Selection */}
216
+ <div className="space-y-4">
217
+ <div className="flex items-center justify-between">
218
+ <h3 className="text-sm font-bold text-slate-800 dark:text-slate-400 uppercase tracking-widest">Select Model</h3>
219
+ </div>
220
+
221
+ <div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
222
+ {MODELS.map((model) => {
223
+ const Icon = model.icon;
224
+ const isSelected = modelChoice === model.id;
225
+ const opacity = isSelected ? 'ring-2 ring-orange-500 bg-orange-50/50 dark:ring-slate-600 dark:bg-slate-800' : 'bg-slate-50 hover:bg-slate-100 dark:bg-[#121930] dark:hover:bg-slate-800/60';
226
+
227
+ return (
228
+ <button
229
+ key={model.id}
230
+ onClick={() => setModelChoice(model.id)}
231
+ className={`relative flex flex-col items-start rounded-2xl border border-slate-200 dark:border-slate-800 p-5 text-left transition-all ${opacity}`}
232
+ >
233
+ {isSelected && <div className="absolute top-4 right-4 h-2 w-2 rounded-full bg-orange-500 shadow-[0_0_8px_rgba(249,115,22,0.6)]" />}
234
+ <div className="flex w-full items-start justify-between mb-4">
235
+ <span className="flex h-10 w-10 items-center justify-center rounded-xl bg-white border border-slate-200 text-slate-700 shadow-sm dark:bg-slate-800 dark:border-slate-700 dark:text-slate-300">
236
+ <Icon size={18} />
237
+ </span>
238
+ <div className="group/tooltip relative">
239
+ <div className="flex h-6 w-6 items-center justify-center rounded-full text-slate-400 hover:text-slate-700 transition cursor-help dark:text-slate-500 dark:hover:text-white">
240
+ <span className="font-serif italic border border-slate-300 dark:border-slate-600 rounded-full w-4 h-4 flex items-center justify-center text-[10px]">i</span>
241
+ </div>
242
+ <div className="absolute right-0 lg:right-auto lg:left-0 top-8 z-50 w-64 opacity-0 scale-95 origin-top-right lg:origin-top-left transition-all group-hover/tooltip:opacity-100 group-hover/tooltip:scale-100 pointer-events-none group-hover/tooltip:pointer-events-auto rounded-xl bg-slate-900 border border-slate-800 p-3 shadow-xl dark:bg-slate-800 dark:border-slate-700">
243
+ <p className="text-xs text-slate-300 leading-relaxed font-normal">{model.description}</p>
244
+ </div>
245
+ </div>
246
+ </div>
247
+ <h4 className="text-lg font-bold text-slate-900 dark:text-white mb-2">{model.name}</h4>
248
+ <span className={`inline-block rounded-full border px-2.5 py-0.5 text-[10px] font-bold uppercase tracking-wider ${model.badgeColor}`}>
249
+ {model.badgeLabel}
250
+ </span>
251
+
252
+ <div className="mt-6 flex w-full items-center justify-between">
253
+ <span className="text-xs font-semibold text-slate-500 dark:text-slate-500">Speed</span>
254
+ <div className="flex gap-1">
255
+ {[1, 2, 3].map((i) => (
256
+ <div key={i} className={`h-1.5 w-1.5 rounded-full ${i <= model.speed ? 'bg-orange-500' : 'bg-slate-300 dark:bg-slate-700'}`} />
257
+ ))}
258
+ </div>
259
+ </div>
260
+ </button>
261
+ );
262
+ })}
263
+ </div>
264
+ </div>
265
+
266
+ {/* Length Slider */}
267
+ <div className="space-y-4 pt-4 border-t border-slate-200 dark:border-slate-800">
268
+ <div className="flex justify-between items-center text-sm font-bold uppercase tracking-widest text-slate-800 dark:text-slate-400 mb-2">
269
+ <span className="flex items-center gap-2"><FileText size={16} /> Summary Length</span>
270
+ <span className="text-orange-500 dark:text-orange-400 tracking-normal text-lg">{maxLength} <span className="text-slate-500 text-xs uppercase ml-1 tracking-widest">words</span></span>
271
+ </div>
272
+ <div className="relative flex items-center pt-2 group">
273
+ <input
274
+ type="range"
275
+ min="20"
276
+ max="400"
277
+ step="4"
278
+ value={maxLength}
279
+ onChange={(e) => setMaxLength(Number(e.target.value))}
280
+ onMouseUp={(e) => { if (text) onSummarize(Number(e.target.value)); }}
281
+ onTouchEnd={(e) => { if (text) onSummarize(Number(e.target.value)); }}
282
+ className="absolute z-10 w-full opacity-0 cursor-pointer h-8 -top-3"
283
+ />
284
+ <div className="h-1.5 w-full rounded-full bg-slate-200 dark:bg-slate-800 overflow-hidden relative">
285
+ <div className="h-full bg-slate-400 dark:bg-slate-600 absolute left-0 top-0 transition-all duration-100 ease-out" style={{width: `${((maxLength-20) / (400-20)) * 100}%`}}></div>
286
+ </div>
287
+ <div className="absolute h-4 w-4 rounded-full border-2 border-orange-500 bg-orange-100 shadow-[0_0_12px_rgba(249,115,22,0.3)] pointer-events-none transition-all duration-100 ease-out group-hover:scale-125 dark:border-orange-500 dark:bg-orange-300 dark:shadow-[0_0_12px_rgba(249,115,22,0.4)]" style={{left: `calc(${((maxLength-20) / (400-20)) * 100}% - 8px)`}}></div>
288
+ </div>
289
+ <div className="flex justify-between text-[11px] font-semibold tracking-widest uppercase text-slate-500 dark:text-slate-600">
290
+ <span>Concise</span>
291
+ <span>Detailed</span>
292
+ </div>
293
+ </div>
294
+
295
+ {/* Button */}
296
+ <div className="mt-6 flex gap-4">
297
+ <button
298
+ onClick={onSummarize}
299
+ disabled={loading}
300
+ className="group flex-1 flex items-center justify-center gap-3 rounded-2xl bg-gradient-to-r from-slate-800 to-slate-900 border border-slate-700 py-4 text-base font-bold text-white shadow-lg transition hover:from-orange-600 hover:to-orange-700 dark:from-orange-500 dark:to-orange-600 focus:ring-4 focus:ring-orange-500/30 disabled:opacity-50"
301
+ >
302
+ {loading ? "Generating Output..." : "Summarize Now"}
303
+ {!loading && <ArrowRight size={18} className="text-white/80 group-hover:text-white transition-colors" />}
304
+ </button>
305
+ </div>
306
+ </div>
307
+ </div>
308
+ </div>
309
+ );
310
+ }
frontend/src/components/SummaryCard.jsx ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Copy, Download } from "lucide-react";
2
+
3
+ function downloadTextFile(filename, content) {
4
+ const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
5
+ const url = URL.createObjectURL(blob);
6
+ const link = document.createElement("a");
7
+ link.href = url;
8
+ link.download = filename;
9
+ document.body.appendChild(link);
10
+ link.click();
11
+ link.remove();
12
+ URL.revokeObjectURL(url);
13
+ }
14
+
15
+ export default function SummaryCard({ title, content, accent = "from-slate-900 to-indigo-700", meta = null }) {
16
+ const safeContent = content || "Run the model to generate a summary.";
17
+
18
+ return (
19
+ <div className="overflow-hidden rounded-[36px] border border-white/60 bg-white/80 shadow-2xl backdrop-blur">
20
+ <div className={`bg-gradient-to-r ${accent} p-8 text-white`}>
21
+ <div className="flex items-center justify-between gap-3">
22
+ <div>
23
+ <div className="text-[10px] font-bold uppercase tracking-[0.2em] text-white/70">Generated Model Output</div>
24
+ <h3 className="mt-2 text-2xl font-bold">{title.replace("Output · ", "")}</h3>
25
+ </div>
26
+ <div className="flex h-12 w-12 items-center justify-center rounded-2xl bg-white/10 text-sm font-bold shadow-inner backdrop-blur" title={`${content ? safeContent.split(/\\s+/).filter(Boolean).length : 0} words`}>
27
+ {content ? safeContent.split(/\s+/).filter(Boolean).length : 0}
28
+ <span className="sr-only">words</span>
29
+ </div>
30
+ </div>
31
+ </div>
32
+ <div className="space-y-6 p-8">
33
+ {meta ? <div className="rounded-2xl bg-slate-100/80 px-4 py-3 text-xs font-semibold uppercase tracking-wider text-slate-500 shadow-sm">{meta}</div> : null}
34
+ <div className="min-h-[140px]">
35
+ <p className="whitespace-pre-wrap text-lg leading-relaxed text-slate-800">{safeContent}</p>
36
+ </div>
37
+ <div className="flex flex-wrap gap-4 pt-4 border-t border-slate-100">
38
+ <button
39
+ type="button"
40
+ onClick={() => navigator.clipboard.writeText(safeContent)}
41
+ className="inline-flex flex-1 items-center justify-center gap-2 rounded-2xl bg-slate-900 px-5 py-3.5 text-sm font-bold text-white shadow-lg transition hover:scale-[1.02] hover:bg-slate-800"
42
+ >
43
+ <Copy size={18} /> Copy
44
+ </button>
45
+ <button
46
+ type="button"
47
+ onClick={() => downloadTextFile(`${title.replace(/\s+/g, "_").toLowerCase()}.txt`, safeContent)}
48
+ className="inline-flex flex-1 items-center justify-center gap-2 rounded-2xl border-2 border-slate-200 bg-white px-5 py-3.5 text-sm font-bold text-slate-700 shadow-sm transition hover:scale-[1.02] hover:border-slate-300 hover:bg-slate-50"
49
+ >
50
+ <Download size={18} /> Save
51
+ </button>
52
+ </div>
53
+ </div>
54
+ </div>
55
+ );
56
+ }
frontend/src/components/TextInputPanel.jsx ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export default function TextInputPanel({ value, onChange }) {
2
+ const wordCount = value.trim() ? value.trim().split(/\s+/).length : 0;
3
+
4
+ return (
5
+ <div className="space-y-4 rounded-3xl border border-white/60 bg-white/70 p-4 shadow-sm backdrop-blur">
6
+ <div className="flex items-center justify-between">
7
+ <label className="block text-xs font-semibold uppercase tracking-[0.18em] text-slate-400">Input: Traffic Incident Description</label>
8
+ <span className="rounded-full bg-slate-100 px-3 py-1 text-xs font-bold text-slate-600 shadow-sm">
9
+ {wordCount} words
10
+ </span>
11
+ </div>
12
+ <textarea
13
+ className="min-h-[220px] w-full resize-y rounded-2xl border-none bg-white p-5 text-base leading-7 text-slate-800 shadow-sm outline-none transition-all placeholder:text-slate-300 focus:ring-4 focus:ring-sky-500/20"
14
+ placeholder="Paste an accident or traffic incident description here..."
15
+ value={value}
16
+ onChange={(e) => onChange(e.target.value)}
17
+ />
18
+ </div>
19
+ );
20
+ }
frontend/src/index.css ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ :root {
6
+ color-scheme: light;
7
+ font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
8
+ }
9
+
10
+ body {
11
+ margin: 0;
12
+ min-width: 320px;
13
+ min-height: 100vh;
14
+ color: #0f172a;
15
+ background: #eef4ff;
16
+ }
17
+
18
+ * {
19
+ box-sizing: border-box;
20
+ }
21
+
22
+ .line-clamp-5 {
23
+ display: -webkit-box;
24
+ -webkit-line-clamp: 5;
25
+ -webkit-box-orient: vertical;
26
+ overflow: hidden;
27
+ }
frontend/src/main.jsx ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ import React from "react";
2
+ import ReactDOM from "react-dom/client";
3
+ import App from "./App";
4
+ import "./index.css";
5
+ ReactDOM.createRoot(document.getElementById("root")).render(<React.StrictMode><App /></React.StrictMode>);
frontend/src/pages/Home.jsx ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useEffect, useRef, useState } from "react";
2
+ import { fetchSamples, summarizeText } from "../api/client";
3
+ import BatchUpload from "../components/BatchUpload";
4
+ import DatasetToggle from "../components/DatasetToggle";
5
+ import SampleGallery from "../components/SampleGallery";
6
+ import SummarizerWidget, { MODELS } from "../components/SummarizerWidget";
7
+ import { Moon, Sun } from "lucide-react";
8
+
9
+ const FALLBACK_TEXT = {
10
+ gcc: "A rear-end collision involving two vehicles was recorded on Sheikh Zayed Road in Dubai during the evening peak. The incident caused a temporary lane closure, minor injuries, and congestion extending into the surrounding corridor while responders managed the scene.",
11
+ us: "A crash involving multiple vehicles blocked the two right lanes on I-95 northbound near Exit 42 in the afternoon commute, causing heavy delays and slow traffic through the corridor. Emergency responders were dispatched to the scene and drivers were advised to use caution."
12
+ };
13
+
14
+ export default function Home() {
15
+ const [isDark, setIsDark] = useState(true);
16
+ const [datasetTrack, setDatasetTrack] = useState("gcc");
17
+ const [text, setText] = useState(FALLBACK_TEXT.gcc);
18
+ const [modelChoice, setModelChoice] = useState("bart_large_cnn");
19
+ const [maxLength, setMaxLength] = useState(150);
20
+ const [summary, setSummary] = useState("");
21
+ const [samples, setSamples] = useState([]);
22
+ const [loading, setLoading] = useState(false);
23
+
24
+ // Refs so async callbacks always see the latest values (avoids stale closures)
25
+ const textRef = useRef(text);
26
+ const maxLengthRef = useRef(maxLength);
27
+ const datasetTrackRef = useRef(datasetTrack);
28
+ useEffect(() => { textRef.current = text; }, [text]);
29
+ useEffect(() => { maxLengthRef.current = maxLength; }, [maxLength]);
30
+ useEffect(() => { datasetTrackRef.current = datasetTrack; }, [datasetTrack]);
31
+
32
+ useEffect(() => {
33
+ if (isDark) {
34
+ document.documentElement.classList.add("dark");
35
+ } else {
36
+ document.documentElement.classList.remove("dark");
37
+ }
38
+ }, [isDark]);
39
+
40
+ useEffect(() => {
41
+ let active = true;
42
+ fetchSamples(datasetTrack)
43
+ .then((items) => {
44
+ if (!active) return;
45
+ setSamples(items);
46
+ setText(items.length ? items[0].text : FALLBACK_TEXT[datasetTrack]);
47
+ })
48
+ .catch(() => {
49
+ if (!active) return;
50
+ setSamples([]);
51
+ setText(FALLBACK_TEXT[datasetTrack]);
52
+ });
53
+ setSummary("");
54
+ return () => { active = false; };
55
+ }, [datasetTrack]);
56
+
57
+ // Single source of truth for summarization — reads from refs to avoid stale state
58
+ const runSummarize = async (modelId, overrideLength = null) => {
59
+ const currentText = textRef.current;
60
+ const currentLength = overrideLength !== null ? overrideLength : maxLengthRef.current;
61
+ const currentTrack = datasetTrackRef.current;
62
+ if (!currentText) return;
63
+ setLoading(true);
64
+ setSummary("");
65
+ try {
66
+ const data = await summarizeText({
67
+ text: currentText,
68
+ model_choice: modelId,
69
+ max_length: currentLength,
70
+ dataset_track: currentTrack
71
+ });
72
+ setSummary(data.summary);
73
+ } catch (error) {
74
+ setSummary(`Error: ${error?.response?.data?.detail || error.message}`);
75
+ } finally {
76
+ setLoading(false);
77
+ }
78
+ };
79
+
80
+ // Called by Summarize Now button and slider release
81
+ const handleSummarize = (overrideLength = null) => {
82
+ if (overrideLength !== null) setMaxLength(overrideLength);
83
+ runSummarize(modelChoice, overrideLength);
84
+ };
85
+
86
+ // Called when user clicks a model card — immediately re-runs with that model
87
+ const handleModelSelect = (modelId) => {
88
+ setModelChoice(modelId);
89
+ runSummarize(modelId);
90
+ };
91
+
92
+ return (
93
+ <div className="min-h-screen bg-slate-50 text-slate-900 transition-colors duration-300 dark:bg-[#0B1021] dark:text-slate-200 pb-16">
94
+
95
+ {/* Header */}
96
+ <header className="flex h-16 items-center justify-between px-6 border-b border-slate-200 dark:border-slate-800 bg-white/50 dark:bg-[#0B1021]/50 backdrop-blur-md sticky top-0 z-40">
97
+ <div className="flex items-center gap-2">
98
+ <div className="h-6 w-6 rounded border-2 border-orange-500 bg-orange-100 dark:bg-orange-500/20"></div>
99
+ <span className="font-black text-lg tracking-tight">TRAFFIC<span className="text-orange-500 font-normal">AI</span></span>
100
+ </div>
101
+ <button
102
+ onClick={() => setIsDark(!isDark)}
103
+ className="p-2 rounded-full bg-slate-100 hover:bg-slate-200 text-slate-600 transition dark:bg-slate-800 dark:hover:bg-slate-700 dark:text-slate-400"
104
+ >
105
+ {isDark ? <Sun size={18} /> : <Moon size={18} />}
106
+ </button>
107
+ </header>
108
+
109
+ <div className="mx-auto max-w-[1500px] px-4 pt-5 grid grid-cols-1 xl:grid-cols-12 gap-8 lg:gap-12 items-start">
110
+
111
+ {/* Left Column */}
112
+ <div className="xl:col-span-8 flex flex-col xl:pl-4">
113
+ <SummarizerWidget
114
+ text={text}
115
+ setText={setText}
116
+ maxLength={maxLength}
117
+ setMaxLength={setMaxLength}
118
+ modelChoice={modelChoice}
119
+ setModelChoice={handleModelSelect}
120
+ onSummarize={handleSummarize}
121
+ loading={loading}
122
+ summary={summary}
123
+ />
124
+ </div>
125
+
126
+ {/* Right Sidebar */}
127
+ <div className="xl:col-span-4 flex flex-col xl:pr-4 pt-5 gap-5">
128
+
129
+ {/* Dataset Track Toggle — always at top */}
130
+ <DatasetToggle value={datasetTrack} onChange={setDatasetTrack} />
131
+
132
+ {/* Dataset Preview — no artificial spacer, sits right below toggle */}
133
+ <div className="rounded-[24px] border border-slate-200 bg-white p-6 shadow-sm dark:border-slate-800 dark:bg-[#0d1326] dark:shadow-xl overflow-hidden">
134
+ <div className="mb-5">
135
+ <h2 className="text-xl font-bold text-slate-900 dark:text-white">Dataset Preview</h2>
136
+ <p className="text-sm text-slate-500 dark:text-slate-400 mt-1">Select a sample to load it into the editor</p>
137
+ </div>
138
+ <div className="overflow-y-auto max-h-[560px] pr-1 space-y-4 custom-scroll">
139
+ <SampleGallery items={samples} onPick={setText} />
140
+ </div>
141
+ </div>
142
+
143
+ {/* Batch Upload */}
144
+ <BatchUpload />
145
+
146
+ </div>
147
+ </div>
148
+ </div>
149
+ );
150
+ }
frontend/tailwind.config.js ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ /** @type {import('tailwindcss').Config} */
2
+ export default { darkMode: "class", content: ["./index.html", "./src/**/*.{js,jsx}"], theme: { extend: {} }, plugins: [] };
frontend/vite.config.js ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ import { defineConfig } from "vite";
2
+ import react from "@vitejs/plugin-react";
3
+ export default defineConfig({ plugins: [react()], server: { port: 5173 } });
notebooks/01_data_exploration.ipynb ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "8f2bf560",
6
+ "metadata": {},
7
+ "source": [
8
+ "# Data Exploration\n",
9
+ "Load the U.S. Accidents dataset, inspect the Description field, and validate the text filtering logic."
10
+ ]
11
+ },
12
+ {
13
+ "cell_type": "code",
14
+ "execution_count": null,
15
+ "id": "811a068e",
16
+ "metadata": {},
17
+ "outputs": [],
18
+ "source": [
19
+ "import pandas as pd\n",
20
+ "from pathlib import Path\n",
21
+ "path = Path('../data/raw/US_Accidents_March23.csv')\n",
22
+ "if path.exists():\n",
23
+ " df = pd.read_csv(path, low_memory=False)\n",
24
+ " print(df[['Description']].head())\n",
25
+ " print(df['Description'].str.len().describe())\n",
26
+ "else:\n",
27
+ " print('Place the Kaggle CSV under data/raw/ before running this notebook.')"
28
+ ]
29
+ }
30
+ ],
31
+ "metadata": {},
32
+ "nbformat": 4,
33
+ "nbformat_minor": 5
34
+ }
notebooks/02_model_evaluation.ipynb ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "9e49735d",
6
+ "metadata": {},
7
+ "source": [
8
+ "# Model Evaluation\n",
9
+ "Generate summaries for the manual evaluation set and compare model outputs."
10
+ ]
11
+ },
12
+ {
13
+ "cell_type": "code",
14
+ "execution_count": null,
15
+ "id": "2c44453f",
16
+ "metadata": {},
17
+ "outputs": [],
18
+ "source": [
19
+ "import pandas as pd\n",
20
+ "from src.models.registry import summarize_text\n",
21
+ "\n",
22
+ "eval_path = '../data/processed/eval_set_with_refs.csv'\n",
23
+ "df = pd.read_csv(eval_path)\n",
24
+ "text = df.iloc[0]['Description']\n",
25
+ "print('Source:', text)\n",
26
+ "for model_name in ['lead1', 'textrank', 'flan_t5_small']:\n",
27
+ " summary = summarize_text(text, model_name)\n",
28
+ " print('\\n', model_name, ':', summary)"
29
+ ]
30
+ },
31
+ {
32
+ "cell_type": "code",
33
+ "execution_count": null,
34
+ "id": "235752ff",
35
+ "metadata": {},
36
+ "outputs": [],
37
+ "source": [
38
+ "import pandas as pd\n",
39
+ "from src.evaluate.eval import evaluate_outputs\n",
40
+ "from src.evaluate.tables import aggregate_metrics_table\n",
41
+ "\n",
42
+ "outputs = pd.read_csv('../data/processed/model_outputs.csv')\n",
43
+ "detailed = evaluate_outputs(outputs)\n",
44
+ "aggregate = aggregate_metrics_table(detailed)\n",
45
+ "aggregate"
46
+ ]
47
+ }
48
+ ],
49
+ "metadata": {},
50
+ "nbformat": 4,
51
+ "nbformat_minor": 5
52
+ }
notebooks/03_results_for_paper.ipynb ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "id": "c726ae1e",
6
+ "metadata": {},
7
+ "source": [
8
+ "# Results for Paper\n",
9
+ "Create charts and export tables for the IEEE paper and poster."
10
+ ]
11
+ },
12
+ {
13
+ "cell_type": "code",
14
+ "execution_count": null,
15
+ "id": "5a4837d2",
16
+ "metadata": {},
17
+ "outputs": [],
18
+ "source": [
19
+ "import pandas as pd\n",
20
+ "import matplotlib.pyplot as plt\n",
21
+ "\n",
22
+ "metrics = pd.read_csv('../data/processed/aggregate_metrics.csv')\n",
23
+ "ax = metrics.set_index('model_name')[['rouge1_f1', 'rouge2_f1', 'rougeL_f1']].plot(kind='bar', figsize=(10, 6))\n",
24
+ "ax.set_title('ROUGE Comparison Across Models')\n",
25
+ "ax.set_ylabel('F1 Score')\n",
26
+ "plt.tight_layout()\n",
27
+ "plt.show()"
28
+ ]
29
+ }
30
+ ],
31
+ "metadata": {},
32
+ "nbformat": 4,
33
+ "nbformat_minor": 5
34
+ }
pyproject.toml ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "traffic-incident-summarization"
7
+ version = "0.1.0"
8
+ description = "Comparative summarization of traffic incident reports with transformer and extractive baselines"
9
+ requires-python = ">=3.11"
10
+ authors = [{name = "Rajeev Ranjan Pandey"}]
11
+
12
+ [tool.pytest.ini_options]
13
+ pythonpath = ["."]
14
+ testpaths = ["tests"]
requirements.txt ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ torch
2
+ transformers
3
+ sentencepiece
4
+ accelerate
5
+ pandas
6
+ numpy
7
+ scikit-learn
8
+ matplotlib
9
+ jupyter
10
+ notebook
11
+ pyyaml
12
+ tqdm
13
+ nltk
14
+ sumy
15
+ networkx
16
+ rouge-score
17
+ evaluate
18
+ fastapi
19
+ uvicorn[standard]
20
+ pydantic
21
+ python-multipart
22
+ requests
23
+ kaggle
scripts/download_notes.md ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Automatic Dataset Download
2
+
3
+ The repo tries to fetch the dataset automatically when you run:
4
+
5
+ ```bash
6
+ python -m src.cli.run_prepare
7
+ ```
8
+
9
+ ## Authentication
10
+ Use one of these:
11
+ - `~/.kaggle/kaggle.json`
12
+ - `KAGGLE_USERNAME` and `KAGGLE_KEY`
13
+
14
+ ## Manual fallback
15
+ If automatic download is not available in your environment, manually download:
16
+ `US_Accidents_March23.csv`
17
+
18
+ Then place it in:
19
+ `data/raw/US_Accidents_March23.csv`
scripts/export_results.sh ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ mkdir -p docs/paper/tables docs/paper/figures
3
+ cp data/processed/aggregate_metrics.csv docs/paper/tables/aggregate_metrics.csv
scripts/run_local_backend.sh ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ source .venv/bin/activate
3
+ uvicorn backend.main:app --reload --port 8000
scripts/run_local_frontend.sh ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ cd frontend
3
+ npm install
4
+ npm run dev