Alleinzellgaenger commited on
Commit
c075953
·
1 Parent(s): 2f3ecea

Before I make bigger changes, let's commit so we have the PDF viewer ready :)

Browse files
.gitignore ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Environment variables
2
+ .env
3
+ .env.local
4
+ .env.production
5
+
6
+ # API keys
7
+ *.key
8
+
9
+ # Python
10
+ __pycache__/
11
+ *.pyc
12
+ *.pyo
13
+
14
+ # Node
15
+ node_modules/
16
+ dist/
17
+
18
+ # IDE
19
+ .vscode/
20
+ .idea/
backend/__init__.py ADDED
File without changes
backend/app.py CHANGED
@@ -1,17 +1,16 @@
1
- from fastapi import FastAPI, HTTPException, Body
2
  from fastapi.middleware.cors import CORSMiddleware
3
- from fastapi.staticfiles import StaticFiles
4
- from fastapi.responses import FileResponse
5
- from transformers import BertTokenizer, BertModel, pipeline
6
- import torch as t
7
- import logging
8
 
9
- logging.basicConfig(level=logging.INFO)
10
- logger = logging.getLogger(__name__)
11
 
12
  app = FastAPI()
13
 
14
- # Configure CORS: In production, you might restrict allowed origins
15
  app.add_middleware(
16
  CORSMiddleware,
17
  allow_origins=["*"],
@@ -19,77 +18,190 @@ app.add_middleware(
19
  allow_headers=["*"],
20
  )
21
 
22
- # Mount static files for React app assets (CSS, JS)
23
- app.mount("/assets", StaticFiles(directory="frontend/assets"), name="assets")
24
-
25
- # Mount other static files (images, etc.)
26
- app.mount("/static", StaticFiles(directory="frontend"), name="static")
27
 
28
- # Load tokenizer and BERT model
29
- tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
30
- try:
31
- model = BertModel.from_pretrained('bert-base-uncased', output_attentions=True)
32
- except Exception as e:
33
- logger.error(f"Model loading failed: {e}")
34
- raise
35
 
36
- @app.post("/process")
37
- async def process_text(text: str = Body(..., embed=True)):
38
- """
39
- Process the input text:
40
- - Tokenizes the text using BERT's tokenizer
41
- - Runs the BERT model to obtain attentions (bidirectional)
42
- - Returns the tokens and attention values (rounded to 2 decimals)
43
- """
 
 
 
44
  try:
45
- logger.info(f"Received text: {text}")
46
- # Tokenize input text (truncating if needed)
47
- inputs = tokenizer(text, return_tensors="pt", truncation=True, max_length=512)
48
-
49
- # Run the model without gradient computation (inference mode)
50
- with t.no_grad():
51
- outputs = model(**inputs)
52
- attentions = outputs.attentions # Tuple of attention tensors for each layer
53
-
54
- decimals = 2
55
- # Convert attention tensors to lists with rounded decimals
56
- attn_series = t.round(
57
- t.tensor([layer_attention.tolist() for layer_attention in attentions], dtype=t.double)
58
- .squeeze(), decimals=decimals
59
- ).detach().cpu().tolist()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  return {
62
- "tokens": tokenizer.convert_ids_to_tokens(inputs["input_ids"][0]),
63
- "attention": attn_series
 
 
64
  }
 
65
  except Exception as e:
66
- logger.error(f"Error processing text: {e}")
67
- raise HTTPException(status_code=500, detail=str(e))
68
 
69
- # Initialize the text generation pipeline (unchanged)
70
- pipe = pipeline("text2text-generation", model="google/flan-t5-small")
71
-
72
- @app.get("/generate")
73
- def generate(text: str):
74
- """
75
- Using the text2text-generation pipeline from `transformers`, generate text
76
- from the given input text. The model used is `google/flan-t5-small`.
77
- """
78
- # Use the pipeline to generate text from the given input text
79
- output = pipe(text)
80
- # Return the generated text in a JSON response
81
- return {"output": output[0]["generated_text"]}
82
-
83
- @app.get("/")
84
- async def read_index():
85
- return FileResponse("frontend/index.html")
86
-
87
- @app.get("/{file_path:path}")
88
- async def serve_static_files(file_path: str):
89
- """Serve static files from frontend directory"""
90
- import os
91
- full_path = f"frontend/{file_path}"
92
- if os.path.exists(full_path) and os.path.isfile(full_path):
93
- return FileResponse(full_path)
94
- # If file not found, serve index.html for React Router
95
- return FileResponse("frontend/index.html")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, File, UploadFile, HTTPException
2
  from fastapi.middleware.cors import CORSMiddleware
3
+ from mistralai import Mistral
4
+ import os
5
+ import tempfile
6
+ from dotenv import load_dotenv
 
7
 
8
+ # Load environment variables
9
+ load_dotenv()
10
 
11
  app = FastAPI()
12
 
13
+ # Enable CORS
14
  app.add_middleware(
15
  CORSMiddleware,
16
  allow_origins=["*"],
 
18
  allow_headers=["*"],
19
  )
20
 
21
+ @app.get("/")
22
+ def hello():
23
+ return {"message": "Backend is running!"}
 
 
24
 
25
+ @app.get("/api/test")
26
+ def test():
27
+ return {"status": "OK", "app": "SokratesAI"}
 
 
 
 
28
 
29
+ @app.post("/upload_pdf")
30
+ async def upload_pdf(file: UploadFile = File(...)):
31
+ """Upload PDF to Mistral Document AI"""
32
+ print(f"📄 Processing file: {file.filename}")
33
+
34
+ # Get Mistral API key
35
+ api_key = os.environ.get("MISTRAL_API_KEY")
36
+ if not api_key:
37
+ print("❌ No Mistral API key found")
38
+ raise HTTPException(status_code=500, detail="MISTRAL_API_KEY not set in environment")
39
+
40
  try:
41
+ # Initialize Mistral client
42
+ client = Mistral(api_key=api_key)
43
+ print("🔑 Mistral client initialized")
44
+
45
+ # Read PDF bytes
46
+ file_bytes = await file.read()
47
+ print(f"📊 File size: {len(file_bytes)} bytes")
48
+
49
+ # Create temporary file for Mistral upload
50
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as temp_file:
51
+ temp_file.write(file_bytes)
52
+ temp_file_path = temp_file.name
53
+
54
+ try:
55
+ print("🚀 Uploading to Mistral...")
56
+
57
+ # Upload PDF to Mistral for OCR processing
58
+ uploaded_pdf = client.files.upload(
59
+ file={
60
+ "file_name": file.filename or "document.pdf",
61
+ "content": open(temp_file_path, "rb"),
62
+ },
63
+ purpose="ocr"
64
+ )
65
+
66
+ print(f"✅ Upload successful! File ID: {uploaded_pdf.id}")
67
+
68
+ return {
69
+ "message": "PDF uploaded to Mistral successfully!",
70
+ "file_id": uploaded_pdf.id,
71
+ "filename": file.filename,
72
+ "status": "uploaded",
73
+ "mistral_response": str(uploaded_pdf)
74
+ }
75
+
76
+ finally:
77
+ # Clean up temporary file
78
+ os.unlink(temp_file_path)
79
+ print("🗑️ Temporary file cleaned up")
80
+
81
+ except Exception as e:
82
+ print(f"❌ Error with Mistral API: {e}")
83
+ raise HTTPException(status_code=500, detail=f"Mistral API error: {str(e)}")
84
 
85
+ @app.get("/process_ocr/{file_id}")
86
+ async def process_ocr_content(file_id: str):
87
+ """Process OCR content using proper Mistral OCR API"""
88
+ print(f"🔍 Processing OCR for file ID: {file_id}")
89
+
90
+ # Get Mistral API key
91
+ api_key = os.environ.get("MISTRAL_API_KEY")
92
+ if not api_key:
93
+ raise HTTPException(status_code=500, detail="MISTRAL_API_KEY not set")
94
+
95
+ try:
96
+ # Initialize Mistral client
97
+ client = Mistral(api_key=api_key)
98
+
99
+ # Get signed URL for the file
100
+ print("🔗 Getting signed URL...")
101
+ signed_url = client.files.get_signed_url(file_id=file_id, expiry=1)
102
+ print(f"✅ Signed URL obtained")
103
+
104
+ # Process OCR using the proper API
105
+ print("🚀 Processing OCR...")
106
+ ocr_response = client.ocr.process(
107
+ model="mistral-ocr-latest",
108
+ document={
109
+ "type": "document_url",
110
+ "document_url": signed_url.url,
111
+ },
112
+ include_image_base64=True # Include images for full processing
113
+ )
114
+
115
+ print(f"✅ OCR processing complete! Found {len(ocr_response.pages)} pages")
116
+
117
+ # Process each page and extract structured data
118
+ processed_pages = []
119
+ for page_idx, page in enumerate(ocr_response.pages):
120
+ print(f"📄 Page {page_idx + 1}: {len(page.markdown)} chars, {len(page.images)} images")
121
+
122
+ page_data = {
123
+ "index": page.index,
124
+ "markdown": page.markdown,
125
+ "images": [],
126
+ "dimensions": {
127
+ "dpi": page.dimensions.dpi,
128
+ "height": page.dimensions.height,
129
+ "width": page.dimensions.width
130
+ }
131
+ }
132
+
133
+ # Process images with coordinates
134
+ for img in page.images:
135
+ image_data = {
136
+ "id": img.id,
137
+ "coordinates": {
138
+ "top_left_x": img.top_left_x,
139
+ "top_left_y": img.top_left_y,
140
+ "bottom_right_x": img.bottom_right_x,
141
+ "bottom_right_y": img.bottom_right_y
142
+ },
143
+ "has_base64": bool(img.image_base64) # Don't include actual base64 in response
144
+ }
145
+ page_data["images"].append(image_data)
146
+
147
+ processed_pages.append(page_data)
148
+
149
+ print(f"📝 Total processed pages: {len(processed_pages)}")
150
+
151
  return {
152
+ "file_id": file_id,
153
+ "pages": processed_pages,
154
+ "total_pages": len(processed_pages),
155
+ "status": "processed"
156
  }
157
+
158
  except Exception as e:
159
+ print(f"Error processing OCR: {e}")
160
+ raise HTTPException(status_code=500, detail=f"Error processing OCR: {str(e)}")
161
 
162
+ @app.get("/get_image/{file_id}/{image_id}")
163
+ async def get_image_base64(file_id: str, image_id: str):
164
+ """Get base64 image data for a specific image"""
165
+ print(f"🖼️ Getting image {image_id} from file {file_id}")
166
+
167
+ # Get Mistral API key
168
+ api_key = os.environ.get("MISTRAL_API_KEY")
169
+ if not api_key:
170
+ raise HTTPException(status_code=500, detail="MISTRAL_API_KEY not set")
171
+
172
+ try:
173
+ # Initialize Mistral client
174
+ client = Mistral(api_key=api_key)
175
+
176
+ # Get signed URL and process OCR again (we could cache this)
177
+ signed_url = client.files.get_signed_url(file_id=file_id, expiry=1)
178
+
179
+ ocr_response = client.ocr.process(
180
+ model="mistral-ocr-latest",
181
+ document={
182
+ "type": "document_url",
183
+ "document_url": signed_url.url,
184
+ },
185
+ include_image_base64=True
186
+ )
187
+
188
+ # Find the requested image
189
+ for page in ocr_response.pages:
190
+ for img in page.images:
191
+ if img.id == image_id:
192
+ return {
193
+ "image_id": image_id,
194
+ "image_base64": img.image_base64,
195
+ "coordinates": {
196
+ "top_left_x": img.top_left_x,
197
+ "top_left_y": img.top_left_y,
198
+ "bottom_right_x": img.bottom_right_x,
199
+ "bottom_right_y": img.bottom_right_y
200
+ }
201
+ }
202
+
203
+ raise HTTPException(status_code=404, detail=f"Image {image_id} not found")
204
+
205
+ except Exception as e:
206
+ print(f"❌ Error getting image: {e}")
207
+ raise HTTPException(status_code=500, detail=f"Error getting image: {str(e)}")
backend/requirements.txt CHANGED
@@ -1,5 +1,5 @@
1
  uvicorn[standard]
2
  fastapi==0.115.7
3
- torch==2.5.1
4
- transformers==4.48.1
5
  python-multipart>=0.0.5
 
 
 
1
  uvicorn[standard]
2
  fastapi==0.115.7
 
 
3
  python-multipart>=0.0.5
4
+ mistralai
5
+ python-dotenv
frontend/package-lock.json CHANGED
@@ -10,11 +10,16 @@
10
  "dependencies": {
11
  "@tailwindcss/postcss": "^4.1.11",
12
  "autoprefixer": "^10.4.21",
 
13
  "postcss": "^8.5.6",
14
  "react": "^18.3.1",
15
  "react-dom": "^18.3.1",
 
 
16
  "react-pdf": "^10.0.1",
17
  "react-router-dom": "^7.7.0",
 
 
18
  "tailwindcss": "^4.1.11"
19
  },
20
  "devDependencies": {
@@ -1823,13 +1828,39 @@
1823
  "@babel/types": "^7.20.7"
1824
  }
1825
  },
 
 
 
 
 
 
 
 
 
1826
  "node_modules/@types/estree": {
1827
  "version": "1.0.8",
1828
  "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
1829
  "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
1830
- "dev": true,
1831
  "license": "MIT"
1832
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1833
  "node_modules/@types/json-schema": {
1834
  "version": "7.0.15",
1835
  "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
@@ -1837,11 +1868,31 @@
1837
  "dev": true,
1838
  "license": "MIT"
1839
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1840
  "node_modules/@types/react": {
1841
  "version": "19.1.8",
1842
  "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz",
1843
  "integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==",
1844
- "devOptional": true,
1845
  "license": "MIT",
1846
  "dependencies": {
1847
  "csstype": "^3.0.2"
@@ -1857,6 +1908,18 @@
1857
  "@types/react": "^19.0.0"
1858
  }
1859
  },
 
 
 
 
 
 
 
 
 
 
 
 
1860
  "node_modules/@vitejs/plugin-react": {
1861
  "version": "4.7.0",
1862
  "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
@@ -1978,6 +2041,16 @@
1978
  "postcss": "^8.1.0"
1979
  }
1980
  },
 
 
 
 
 
 
 
 
 
 
1981
  "node_modules/balanced-match": {
1982
  "version": "1.0.2",
1983
  "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -2058,6 +2131,16 @@
2058
  ],
2059
  "license": "CC-BY-4.0"
2060
  },
 
 
 
 
 
 
 
 
 
 
2061
  "node_modules/chalk": {
2062
  "version": "4.1.2",
2063
  "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -2075,6 +2158,46 @@
2075
  "url": "https://github.com/chalk/chalk?sponsor=1"
2076
  }
2077
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2078
  "node_modules/chownr": {
2079
  "version": "3.0.0",
2080
  "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
@@ -2113,6 +2236,25 @@
2113
  "dev": true,
2114
  "license": "MIT"
2115
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2116
  "node_modules/concat-map": {
2117
  "version": "0.0.1",
2118
  "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -2155,14 +2297,12 @@
2155
  "version": "3.1.3",
2156
  "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
2157
  "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
2158
- "devOptional": true,
2159
  "license": "MIT"
2160
  },
2161
  "node_modules/debug": {
2162
  "version": "4.4.1",
2163
  "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
2164
  "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
2165
- "dev": true,
2166
  "license": "MIT",
2167
  "dependencies": {
2168
  "ms": "^2.1.3"
@@ -2176,6 +2316,19 @@
2176
  }
2177
  }
2178
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
2179
  "node_modules/deep-is": {
2180
  "version": "0.1.4",
2181
  "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@@ -2201,6 +2354,19 @@
2201
  "node": ">=8"
2202
  }
2203
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
2204
  "node_modules/electron-to-chromium": {
2205
  "version": "1.5.190",
2206
  "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.190.tgz",
@@ -2220,6 +2386,18 @@
2220
  "node": ">=10.13.0"
2221
  }
2222
  },
 
 
 
 
 
 
 
 
 
 
 
 
2223
  "node_modules/esbuild": {
2224
  "version": "0.25.8",
2225
  "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz",
@@ -2452,6 +2630,16 @@
2452
  "node": ">=4.0"
2453
  }
2454
  },
 
 
 
 
 
 
 
 
 
 
2455
  "node_modules/esutils": {
2456
  "version": "2.0.3",
2457
  "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
@@ -2462,6 +2650,12 @@
2462
  "node": ">=0.10.0"
2463
  }
2464
  },
 
 
 
 
 
 
2465
  "node_modules/fast-deep-equal": {
2466
  "version": "3.1.3",
2467
  "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -2629,6 +2823,184 @@
2629
  "node": ">=8"
2630
  }
2631
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2632
  "node_modules/ignore": {
2633
  "version": "5.3.2",
2634
  "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -2666,6 +3038,46 @@
2666
  "node": ">=0.8.19"
2667
  }
2668
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2669
  "node_modules/is-extglob": {
2670
  "version": "2.1.1",
2671
  "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -2689,6 +3101,28 @@
2689
  "node": ">=0.10.0"
2690
  }
2691
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2692
  "node_modules/isexe": {
2693
  "version": "2.0.0",
2694
  "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -2771,6 +3205,22 @@
2771
  "node": ">=6"
2772
  }
2773
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2774
  "node_modules/keyv": {
2775
  "version": "4.5.4",
2776
  "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -3046,6 +3496,16 @@
3046
  "dev": true,
3047
  "license": "MIT"
3048
  },
 
 
 
 
 
 
 
 
 
 
3049
  "node_modules/loose-envify": {
3050
  "version": "1.4.0",
3051
  "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -3095,28 +3555,661 @@
3095
  "url": "https://github.com/wojtekmaj/make-event-props?sponsor=1"
3096
  }
3097
  },
3098
- "node_modules/merge-refs": {
3099
- "version": "2.0.0",
3100
- "resolved": "https://registry.npmjs.org/merge-refs/-/merge-refs-2.0.0.tgz",
3101
- "integrity": "sha512-3+B21mYK2IqUWnd2EivABLT7ueDhb0b8/dGK8LoFQPrU61YITeCMn14F7y7qZafWNZhUEKb24cJdiT5Wxs3prg==",
3102
  "license": "MIT",
3103
- "funding": {
3104
- "url": "https://github.com/wojtekmaj/merge-refs?sponsor=1"
3105
- },
3106
- "peerDependencies": {
3107
- "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
 
 
 
 
 
 
 
 
3108
  },
3109
- "peerDependenciesMeta": {
3110
- "@types/react": {
3111
- "optional": true
3112
- }
3113
  }
3114
  },
3115
- "node_modules/minimatch": {
3116
- "version": "3.1.2",
3117
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
3118
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
3119
- "dev": true,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3120
  "license": "ISC",
3121
  "dependencies": {
3122
  "brace-expansion": "^1.1.7"
@@ -3165,7 +4258,6 @@
3165
  "version": "2.1.3",
3166
  "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
3167
  "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
3168
- "dev": true,
3169
  "license": "MIT"
3170
  },
3171
  "node_modules/nanoid": {
@@ -3208,6 +4300,16 @@
3208
  "node": ">=0.10.0"
3209
  }
3210
  },
 
 
 
 
 
 
 
 
 
 
3211
  "node_modules/optionator": {
3212
  "version": "0.9.4",
3213
  "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@@ -3271,6 +4373,43 @@
3271
  "node": ">=6"
3272
  }
3273
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3274
  "node_modules/path-exists": {
3275
  "version": "4.0.0",
3276
  "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -3366,6 +4505,28 @@
3366
  "node": ">= 0.8.0"
3367
  }
3368
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3369
  "node_modules/punycode": {
3370
  "version": "2.3.1",
3371
  "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -3401,6 +4562,53 @@
3401
  "react": "^18.3.1"
3402
  }
3403
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3404
  "node_modules/react-pdf": {
3405
  "version": "10.0.1",
3406
  "resolved": "https://registry.npmjs.org/react-pdf/-/react-pdf-10.0.1.tgz",
@@ -3478,6 +4686,74 @@
3478
  "react-dom": ">=18"
3479
  }
3480
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3481
  "node_modules/resolve-from": {
3482
  "version": "4.0.0",
3483
  "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
@@ -3585,6 +4861,30 @@
3585
  "node": ">=0.10.0"
3586
  }
3587
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3588
  "node_modules/strip-json-comments": {
3589
  "version": "3.1.1",
3590
  "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@@ -3598,6 +4898,24 @@
3598
  "url": "https://github.com/sponsors/sindresorhus"
3599
  }
3600
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3601
  "node_modules/supports-color": {
3602
  "version": "7.2.0",
3603
  "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -3675,6 +4993,26 @@
3675
  "url": "https://github.com/sponsors/SuperchupuDev"
3676
  }
3677
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3678
  "node_modules/type-check": {
3679
  "version": "0.4.0",
3680
  "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -3688,6 +5026,121 @@
3688
  "node": ">= 0.8.0"
3689
  }
3690
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3691
  "node_modules/update-browserslist-db": {
3692
  "version": "1.1.3",
3693
  "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
@@ -3728,6 +5181,48 @@
3728
  "punycode": "^2.1.0"
3729
  }
3730
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3731
  "node_modules/vite": {
3732
  "version": "7.0.6",
3733
  "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.6.tgz",
@@ -3812,6 +5307,16 @@
3812
  "loose-envify": "^1.0.0"
3813
  }
3814
  },
 
 
 
 
 
 
 
 
 
 
3815
  "node_modules/which": {
3816
  "version": "2.0.2",
3817
  "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -3857,6 +5362,16 @@
3857
  "funding": {
3858
  "url": "https://github.com/sponsors/sindresorhus"
3859
  }
 
 
 
 
 
 
 
 
 
 
3860
  }
3861
  }
3862
  }
 
10
  "dependencies": {
11
  "@tailwindcss/postcss": "^4.1.11",
12
  "autoprefixer": "^10.4.21",
13
+ "katex": "^0.16.22",
14
  "postcss": "^8.5.6",
15
  "react": "^18.3.1",
16
  "react-dom": "^18.3.1",
17
+ "react-katex": "^3.1.0",
18
+ "react-markdown": "^10.1.0",
19
  "react-pdf": "^10.0.1",
20
  "react-router-dom": "^7.7.0",
21
+ "rehype-katex": "^7.0.1",
22
+ "remark-math": "^6.0.0",
23
  "tailwindcss": "^4.1.11"
24
  },
25
  "devDependencies": {
 
1828
  "@babel/types": "^7.20.7"
1829
  }
1830
  },
1831
+ "node_modules/@types/debug": {
1832
+ "version": "4.1.12",
1833
+ "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz",
1834
+ "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==",
1835
+ "license": "MIT",
1836
+ "dependencies": {
1837
+ "@types/ms": "*"
1838
+ }
1839
+ },
1840
  "node_modules/@types/estree": {
1841
  "version": "1.0.8",
1842
  "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
1843
  "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
 
1844
  "license": "MIT"
1845
  },
1846
+ "node_modules/@types/estree-jsx": {
1847
+ "version": "1.0.5",
1848
+ "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz",
1849
+ "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==",
1850
+ "license": "MIT",
1851
+ "dependencies": {
1852
+ "@types/estree": "*"
1853
+ }
1854
+ },
1855
+ "node_modules/@types/hast": {
1856
+ "version": "3.0.4",
1857
+ "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz",
1858
+ "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==",
1859
+ "license": "MIT",
1860
+ "dependencies": {
1861
+ "@types/unist": "*"
1862
+ }
1863
+ },
1864
  "node_modules/@types/json-schema": {
1865
  "version": "7.0.15",
1866
  "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
 
1868
  "dev": true,
1869
  "license": "MIT"
1870
  },
1871
+ "node_modules/@types/katex": {
1872
+ "version": "0.16.7",
1873
+ "resolved": "https://registry.npmjs.org/@types/katex/-/katex-0.16.7.tgz",
1874
+ "integrity": "sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==",
1875
+ "license": "MIT"
1876
+ },
1877
+ "node_modules/@types/mdast": {
1878
+ "version": "4.0.4",
1879
+ "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz",
1880
+ "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==",
1881
+ "license": "MIT",
1882
+ "dependencies": {
1883
+ "@types/unist": "*"
1884
+ }
1885
+ },
1886
+ "node_modules/@types/ms": {
1887
+ "version": "2.1.0",
1888
+ "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
1889
+ "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
1890
+ "license": "MIT"
1891
+ },
1892
  "node_modules/@types/react": {
1893
  "version": "19.1.8",
1894
  "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz",
1895
  "integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==",
 
1896
  "license": "MIT",
1897
  "dependencies": {
1898
  "csstype": "^3.0.2"
 
1908
  "@types/react": "^19.0.0"
1909
  }
1910
  },
1911
+ "node_modules/@types/unist": {
1912
+ "version": "3.0.3",
1913
+ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
1914
+ "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
1915
+ "license": "MIT"
1916
+ },
1917
+ "node_modules/@ungap/structured-clone": {
1918
+ "version": "1.3.0",
1919
+ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
1920
+ "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
1921
+ "license": "ISC"
1922
+ },
1923
  "node_modules/@vitejs/plugin-react": {
1924
  "version": "4.7.0",
1925
  "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
 
2041
  "postcss": "^8.1.0"
2042
  }
2043
  },
2044
+ "node_modules/bail": {
2045
+ "version": "2.0.2",
2046
+ "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz",
2047
+ "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==",
2048
+ "license": "MIT",
2049
+ "funding": {
2050
+ "type": "github",
2051
+ "url": "https://github.com/sponsors/wooorm"
2052
+ }
2053
+ },
2054
  "node_modules/balanced-match": {
2055
  "version": "1.0.2",
2056
  "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
 
2131
  ],
2132
  "license": "CC-BY-4.0"
2133
  },
2134
+ "node_modules/ccount": {
2135
+ "version": "2.0.1",
2136
+ "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz",
2137
+ "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==",
2138
+ "license": "MIT",
2139
+ "funding": {
2140
+ "type": "github",
2141
+ "url": "https://github.com/sponsors/wooorm"
2142
+ }
2143
+ },
2144
  "node_modules/chalk": {
2145
  "version": "4.1.2",
2146
  "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
 
2158
  "url": "https://github.com/chalk/chalk?sponsor=1"
2159
  }
2160
  },
2161
+ "node_modules/character-entities": {
2162
+ "version": "2.0.2",
2163
+ "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz",
2164
+ "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==",
2165
+ "license": "MIT",
2166
+ "funding": {
2167
+ "type": "github",
2168
+ "url": "https://github.com/sponsors/wooorm"
2169
+ }
2170
+ },
2171
+ "node_modules/character-entities-html4": {
2172
+ "version": "2.1.0",
2173
+ "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz",
2174
+ "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==",
2175
+ "license": "MIT",
2176
+ "funding": {
2177
+ "type": "github",
2178
+ "url": "https://github.com/sponsors/wooorm"
2179
+ }
2180
+ },
2181
+ "node_modules/character-entities-legacy": {
2182
+ "version": "3.0.0",
2183
+ "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz",
2184
+ "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==",
2185
+ "license": "MIT",
2186
+ "funding": {
2187
+ "type": "github",
2188
+ "url": "https://github.com/sponsors/wooorm"
2189
+ }
2190
+ },
2191
+ "node_modules/character-reference-invalid": {
2192
+ "version": "2.0.1",
2193
+ "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz",
2194
+ "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==",
2195
+ "license": "MIT",
2196
+ "funding": {
2197
+ "type": "github",
2198
+ "url": "https://github.com/sponsors/wooorm"
2199
+ }
2200
+ },
2201
  "node_modules/chownr": {
2202
  "version": "3.0.0",
2203
  "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
 
2236
  "dev": true,
2237
  "license": "MIT"
2238
  },
2239
+ "node_modules/comma-separated-tokens": {
2240
+ "version": "2.0.3",
2241
+ "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz",
2242
+ "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==",
2243
+ "license": "MIT",
2244
+ "funding": {
2245
+ "type": "github",
2246
+ "url": "https://github.com/sponsors/wooorm"
2247
+ }
2248
+ },
2249
+ "node_modules/commander": {
2250
+ "version": "8.3.0",
2251
+ "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
2252
+ "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
2253
+ "license": "MIT",
2254
+ "engines": {
2255
+ "node": ">= 12"
2256
+ }
2257
+ },
2258
  "node_modules/concat-map": {
2259
  "version": "0.0.1",
2260
  "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
 
2297
  "version": "3.1.3",
2298
  "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
2299
  "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
 
2300
  "license": "MIT"
2301
  },
2302
  "node_modules/debug": {
2303
  "version": "4.4.1",
2304
  "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
2305
  "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
 
2306
  "license": "MIT",
2307
  "dependencies": {
2308
  "ms": "^2.1.3"
 
2316
  }
2317
  }
2318
  },
2319
+ "node_modules/decode-named-character-reference": {
2320
+ "version": "1.2.0",
2321
+ "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz",
2322
+ "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==",
2323
+ "license": "MIT",
2324
+ "dependencies": {
2325
+ "character-entities": "^2.0.0"
2326
+ },
2327
+ "funding": {
2328
+ "type": "github",
2329
+ "url": "https://github.com/sponsors/wooorm"
2330
+ }
2331
+ },
2332
  "node_modules/deep-is": {
2333
  "version": "0.1.4",
2334
  "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
 
2354
  "node": ">=8"
2355
  }
2356
  },
2357
+ "node_modules/devlop": {
2358
+ "version": "1.1.0",
2359
+ "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz",
2360
+ "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==",
2361
+ "license": "MIT",
2362
+ "dependencies": {
2363
+ "dequal": "^2.0.0"
2364
+ },
2365
+ "funding": {
2366
+ "type": "github",
2367
+ "url": "https://github.com/sponsors/wooorm"
2368
+ }
2369
+ },
2370
  "node_modules/electron-to-chromium": {
2371
  "version": "1.5.190",
2372
  "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.190.tgz",
 
2386
  "node": ">=10.13.0"
2387
  }
2388
  },
2389
+ "node_modules/entities": {
2390
+ "version": "6.0.1",
2391
+ "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
2392
+ "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
2393
+ "license": "BSD-2-Clause",
2394
+ "engines": {
2395
+ "node": ">=0.12"
2396
+ },
2397
+ "funding": {
2398
+ "url": "https://github.com/fb55/entities?sponsor=1"
2399
+ }
2400
+ },
2401
  "node_modules/esbuild": {
2402
  "version": "0.25.8",
2403
  "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz",
 
2630
  "node": ">=4.0"
2631
  }
2632
  },
2633
+ "node_modules/estree-util-is-identifier-name": {
2634
+ "version": "3.0.0",
2635
+ "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz",
2636
+ "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==",
2637
+ "license": "MIT",
2638
+ "funding": {
2639
+ "type": "opencollective",
2640
+ "url": "https://opencollective.com/unified"
2641
+ }
2642
+ },
2643
  "node_modules/esutils": {
2644
  "version": "2.0.3",
2645
  "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
 
2650
  "node": ">=0.10.0"
2651
  }
2652
  },
2653
+ "node_modules/extend": {
2654
+ "version": "3.0.2",
2655
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
2656
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
2657
+ "license": "MIT"
2658
+ },
2659
  "node_modules/fast-deep-equal": {
2660
  "version": "3.1.3",
2661
  "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
 
2823
  "node": ">=8"
2824
  }
2825
  },
2826
+ "node_modules/hast-util-from-dom": {
2827
+ "version": "5.0.1",
2828
+ "resolved": "https://registry.npmjs.org/hast-util-from-dom/-/hast-util-from-dom-5.0.1.tgz",
2829
+ "integrity": "sha512-N+LqofjR2zuzTjCPzyDUdSshy4Ma6li7p/c3pA78uTwzFgENbgbUrm2ugwsOdcjI1muO+o6Dgzp9p8WHtn/39Q==",
2830
+ "license": "ISC",
2831
+ "dependencies": {
2832
+ "@types/hast": "^3.0.0",
2833
+ "hastscript": "^9.0.0",
2834
+ "web-namespaces": "^2.0.0"
2835
+ },
2836
+ "funding": {
2837
+ "type": "opencollective",
2838
+ "url": "https://opencollective.com/unified"
2839
+ }
2840
+ },
2841
+ "node_modules/hast-util-from-html": {
2842
+ "version": "2.0.3",
2843
+ "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz",
2844
+ "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==",
2845
+ "license": "MIT",
2846
+ "dependencies": {
2847
+ "@types/hast": "^3.0.0",
2848
+ "devlop": "^1.1.0",
2849
+ "hast-util-from-parse5": "^8.0.0",
2850
+ "parse5": "^7.0.0",
2851
+ "vfile": "^6.0.0",
2852
+ "vfile-message": "^4.0.0"
2853
+ },
2854
+ "funding": {
2855
+ "type": "opencollective",
2856
+ "url": "https://opencollective.com/unified"
2857
+ }
2858
+ },
2859
+ "node_modules/hast-util-from-html-isomorphic": {
2860
+ "version": "2.0.0",
2861
+ "resolved": "https://registry.npmjs.org/hast-util-from-html-isomorphic/-/hast-util-from-html-isomorphic-2.0.0.tgz",
2862
+ "integrity": "sha512-zJfpXq44yff2hmE0XmwEOzdWin5xwH+QIhMLOScpX91e/NSGPsAzNCvLQDIEPyO2TXi+lBmU6hjLIhV8MwP2kw==",
2863
+ "license": "MIT",
2864
+ "dependencies": {
2865
+ "@types/hast": "^3.0.0",
2866
+ "hast-util-from-dom": "^5.0.0",
2867
+ "hast-util-from-html": "^2.0.0",
2868
+ "unist-util-remove-position": "^5.0.0"
2869
+ },
2870
+ "funding": {
2871
+ "type": "opencollective",
2872
+ "url": "https://opencollective.com/unified"
2873
+ }
2874
+ },
2875
+ "node_modules/hast-util-from-parse5": {
2876
+ "version": "8.0.3",
2877
+ "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz",
2878
+ "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==",
2879
+ "license": "MIT",
2880
+ "dependencies": {
2881
+ "@types/hast": "^3.0.0",
2882
+ "@types/unist": "^3.0.0",
2883
+ "devlop": "^1.0.0",
2884
+ "hastscript": "^9.0.0",
2885
+ "property-information": "^7.0.0",
2886
+ "vfile": "^6.0.0",
2887
+ "vfile-location": "^5.0.0",
2888
+ "web-namespaces": "^2.0.0"
2889
+ },
2890
+ "funding": {
2891
+ "type": "opencollective",
2892
+ "url": "https://opencollective.com/unified"
2893
+ }
2894
+ },
2895
+ "node_modules/hast-util-is-element": {
2896
+ "version": "3.0.0",
2897
+ "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz",
2898
+ "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==",
2899
+ "license": "MIT",
2900
+ "dependencies": {
2901
+ "@types/hast": "^3.0.0"
2902
+ },
2903
+ "funding": {
2904
+ "type": "opencollective",
2905
+ "url": "https://opencollective.com/unified"
2906
+ }
2907
+ },
2908
+ "node_modules/hast-util-parse-selector": {
2909
+ "version": "4.0.0",
2910
+ "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz",
2911
+ "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==",
2912
+ "license": "MIT",
2913
+ "dependencies": {
2914
+ "@types/hast": "^3.0.0"
2915
+ },
2916
+ "funding": {
2917
+ "type": "opencollective",
2918
+ "url": "https://opencollective.com/unified"
2919
+ }
2920
+ },
2921
+ "node_modules/hast-util-to-jsx-runtime": {
2922
+ "version": "2.3.6",
2923
+ "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz",
2924
+ "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==",
2925
+ "license": "MIT",
2926
+ "dependencies": {
2927
+ "@types/estree": "^1.0.0",
2928
+ "@types/hast": "^3.0.0",
2929
+ "@types/unist": "^3.0.0",
2930
+ "comma-separated-tokens": "^2.0.0",
2931
+ "devlop": "^1.0.0",
2932
+ "estree-util-is-identifier-name": "^3.0.0",
2933
+ "hast-util-whitespace": "^3.0.0",
2934
+ "mdast-util-mdx-expression": "^2.0.0",
2935
+ "mdast-util-mdx-jsx": "^3.0.0",
2936
+ "mdast-util-mdxjs-esm": "^2.0.0",
2937
+ "property-information": "^7.0.0",
2938
+ "space-separated-tokens": "^2.0.0",
2939
+ "style-to-js": "^1.0.0",
2940
+ "unist-util-position": "^5.0.0",
2941
+ "vfile-message": "^4.0.0"
2942
+ },
2943
+ "funding": {
2944
+ "type": "opencollective",
2945
+ "url": "https://opencollective.com/unified"
2946
+ }
2947
+ },
2948
+ "node_modules/hast-util-to-text": {
2949
+ "version": "4.0.2",
2950
+ "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz",
2951
+ "integrity": "sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==",
2952
+ "license": "MIT",
2953
+ "dependencies": {
2954
+ "@types/hast": "^3.0.0",
2955
+ "@types/unist": "^3.0.0",
2956
+ "hast-util-is-element": "^3.0.0",
2957
+ "unist-util-find-after": "^5.0.0"
2958
+ },
2959
+ "funding": {
2960
+ "type": "opencollective",
2961
+ "url": "https://opencollective.com/unified"
2962
+ }
2963
+ },
2964
+ "node_modules/hast-util-whitespace": {
2965
+ "version": "3.0.0",
2966
+ "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz",
2967
+ "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==",
2968
+ "license": "MIT",
2969
+ "dependencies": {
2970
+ "@types/hast": "^3.0.0"
2971
+ },
2972
+ "funding": {
2973
+ "type": "opencollective",
2974
+ "url": "https://opencollective.com/unified"
2975
+ }
2976
+ },
2977
+ "node_modules/hastscript": {
2978
+ "version": "9.0.1",
2979
+ "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz",
2980
+ "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==",
2981
+ "license": "MIT",
2982
+ "dependencies": {
2983
+ "@types/hast": "^3.0.0",
2984
+ "comma-separated-tokens": "^2.0.0",
2985
+ "hast-util-parse-selector": "^4.0.0",
2986
+ "property-information": "^7.0.0",
2987
+ "space-separated-tokens": "^2.0.0"
2988
+ },
2989
+ "funding": {
2990
+ "type": "opencollective",
2991
+ "url": "https://opencollective.com/unified"
2992
+ }
2993
+ },
2994
+ "node_modules/html-url-attributes": {
2995
+ "version": "3.0.1",
2996
+ "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz",
2997
+ "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==",
2998
+ "license": "MIT",
2999
+ "funding": {
3000
+ "type": "opencollective",
3001
+ "url": "https://opencollective.com/unified"
3002
+ }
3003
+ },
3004
  "node_modules/ignore": {
3005
  "version": "5.3.2",
3006
  "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
 
3038
  "node": ">=0.8.19"
3039
  }
3040
  },
3041
+ "node_modules/inline-style-parser": {
3042
+ "version": "0.2.4",
3043
+ "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz",
3044
+ "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==",
3045
+ "license": "MIT"
3046
+ },
3047
+ "node_modules/is-alphabetical": {
3048
+ "version": "2.0.1",
3049
+ "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
3050
+ "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==",
3051
+ "license": "MIT",
3052
+ "funding": {
3053
+ "type": "github",
3054
+ "url": "https://github.com/sponsors/wooorm"
3055
+ }
3056
+ },
3057
+ "node_modules/is-alphanumerical": {
3058
+ "version": "2.0.1",
3059
+ "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz",
3060
+ "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==",
3061
+ "license": "MIT",
3062
+ "dependencies": {
3063
+ "is-alphabetical": "^2.0.0",
3064
+ "is-decimal": "^2.0.0"
3065
+ },
3066
+ "funding": {
3067
+ "type": "github",
3068
+ "url": "https://github.com/sponsors/wooorm"
3069
+ }
3070
+ },
3071
+ "node_modules/is-decimal": {
3072
+ "version": "2.0.1",
3073
+ "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz",
3074
+ "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==",
3075
+ "license": "MIT",
3076
+ "funding": {
3077
+ "type": "github",
3078
+ "url": "https://github.com/sponsors/wooorm"
3079
+ }
3080
+ },
3081
  "node_modules/is-extglob": {
3082
  "version": "2.1.1",
3083
  "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
 
3101
  "node": ">=0.10.0"
3102
  }
3103
  },
3104
+ "node_modules/is-hexadecimal": {
3105
+ "version": "2.0.1",
3106
+ "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz",
3107
+ "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==",
3108
+ "license": "MIT",
3109
+ "funding": {
3110
+ "type": "github",
3111
+ "url": "https://github.com/sponsors/wooorm"
3112
+ }
3113
+ },
3114
+ "node_modules/is-plain-obj": {
3115
+ "version": "4.1.0",
3116
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
3117
+ "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
3118
+ "license": "MIT",
3119
+ "engines": {
3120
+ "node": ">=12"
3121
+ },
3122
+ "funding": {
3123
+ "url": "https://github.com/sponsors/sindresorhus"
3124
+ }
3125
+ },
3126
  "node_modules/isexe": {
3127
  "version": "2.0.0",
3128
  "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
 
3205
  "node": ">=6"
3206
  }
3207
  },
3208
+ "node_modules/katex": {
3209
+ "version": "0.16.22",
3210
+ "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.22.tgz",
3211
+ "integrity": "sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==",
3212
+ "funding": [
3213
+ "https://opencollective.com/katex",
3214
+ "https://github.com/sponsors/katex"
3215
+ ],
3216
+ "license": "MIT",
3217
+ "dependencies": {
3218
+ "commander": "^8.3.0"
3219
+ },
3220
+ "bin": {
3221
+ "katex": "cli.js"
3222
+ }
3223
+ },
3224
  "node_modules/keyv": {
3225
  "version": "4.5.4",
3226
  "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
 
3496
  "dev": true,
3497
  "license": "MIT"
3498
  },
3499
+ "node_modules/longest-streak": {
3500
+ "version": "3.1.0",
3501
+ "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz",
3502
+ "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==",
3503
+ "license": "MIT",
3504
+ "funding": {
3505
+ "type": "github",
3506
+ "url": "https://github.com/sponsors/wooorm"
3507
+ }
3508
+ },
3509
  "node_modules/loose-envify": {
3510
  "version": "1.4.0",
3511
  "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
 
3555
  "url": "https://github.com/wojtekmaj/make-event-props?sponsor=1"
3556
  }
3557
  },
3558
+ "node_modules/mdast-util-from-markdown": {
3559
+ "version": "2.0.2",
3560
+ "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz",
3561
+ "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==",
3562
  "license": "MIT",
3563
+ "dependencies": {
3564
+ "@types/mdast": "^4.0.0",
3565
+ "@types/unist": "^3.0.0",
3566
+ "decode-named-character-reference": "^1.0.0",
3567
+ "devlop": "^1.0.0",
3568
+ "mdast-util-to-string": "^4.0.0",
3569
+ "micromark": "^4.0.0",
3570
+ "micromark-util-decode-numeric-character-reference": "^2.0.0",
3571
+ "micromark-util-decode-string": "^2.0.0",
3572
+ "micromark-util-normalize-identifier": "^2.0.0",
3573
+ "micromark-util-symbol": "^2.0.0",
3574
+ "micromark-util-types": "^2.0.0",
3575
+ "unist-util-stringify-position": "^4.0.0"
3576
  },
3577
+ "funding": {
3578
+ "type": "opencollective",
3579
+ "url": "https://opencollective.com/unified"
 
3580
  }
3581
  },
3582
+ "node_modules/mdast-util-math": {
3583
+ "version": "3.0.0",
3584
+ "resolved": "https://registry.npmjs.org/mdast-util-math/-/mdast-util-math-3.0.0.tgz",
3585
+ "integrity": "sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==",
3586
+ "license": "MIT",
3587
+ "dependencies": {
3588
+ "@types/hast": "^3.0.0",
3589
+ "@types/mdast": "^4.0.0",
3590
+ "devlop": "^1.0.0",
3591
+ "longest-streak": "^3.0.0",
3592
+ "mdast-util-from-markdown": "^2.0.0",
3593
+ "mdast-util-to-markdown": "^2.1.0",
3594
+ "unist-util-remove-position": "^5.0.0"
3595
+ },
3596
+ "funding": {
3597
+ "type": "opencollective",
3598
+ "url": "https://opencollective.com/unified"
3599
+ }
3600
+ },
3601
+ "node_modules/mdast-util-mdx-expression": {
3602
+ "version": "2.0.1",
3603
+ "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz",
3604
+ "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==",
3605
+ "license": "MIT",
3606
+ "dependencies": {
3607
+ "@types/estree-jsx": "^1.0.0",
3608
+ "@types/hast": "^3.0.0",
3609
+ "@types/mdast": "^4.0.0",
3610
+ "devlop": "^1.0.0",
3611
+ "mdast-util-from-markdown": "^2.0.0",
3612
+ "mdast-util-to-markdown": "^2.0.0"
3613
+ },
3614
+ "funding": {
3615
+ "type": "opencollective",
3616
+ "url": "https://opencollective.com/unified"
3617
+ }
3618
+ },
3619
+ "node_modules/mdast-util-mdx-jsx": {
3620
+ "version": "3.2.0",
3621
+ "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz",
3622
+ "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==",
3623
+ "license": "MIT",
3624
+ "dependencies": {
3625
+ "@types/estree-jsx": "^1.0.0",
3626
+ "@types/hast": "^3.0.0",
3627
+ "@types/mdast": "^4.0.0",
3628
+ "@types/unist": "^3.0.0",
3629
+ "ccount": "^2.0.0",
3630
+ "devlop": "^1.1.0",
3631
+ "mdast-util-from-markdown": "^2.0.0",
3632
+ "mdast-util-to-markdown": "^2.0.0",
3633
+ "parse-entities": "^4.0.0",
3634
+ "stringify-entities": "^4.0.0",
3635
+ "unist-util-stringify-position": "^4.0.0",
3636
+ "vfile-message": "^4.0.0"
3637
+ },
3638
+ "funding": {
3639
+ "type": "opencollective",
3640
+ "url": "https://opencollective.com/unified"
3641
+ }
3642
+ },
3643
+ "node_modules/mdast-util-mdxjs-esm": {
3644
+ "version": "2.0.1",
3645
+ "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz",
3646
+ "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==",
3647
+ "license": "MIT",
3648
+ "dependencies": {
3649
+ "@types/estree-jsx": "^1.0.0",
3650
+ "@types/hast": "^3.0.0",
3651
+ "@types/mdast": "^4.0.0",
3652
+ "devlop": "^1.0.0",
3653
+ "mdast-util-from-markdown": "^2.0.0",
3654
+ "mdast-util-to-markdown": "^2.0.0"
3655
+ },
3656
+ "funding": {
3657
+ "type": "opencollective",
3658
+ "url": "https://opencollective.com/unified"
3659
+ }
3660
+ },
3661
+ "node_modules/mdast-util-phrasing": {
3662
+ "version": "4.1.0",
3663
+ "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz",
3664
+ "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==",
3665
+ "license": "MIT",
3666
+ "dependencies": {
3667
+ "@types/mdast": "^4.0.0",
3668
+ "unist-util-is": "^6.0.0"
3669
+ },
3670
+ "funding": {
3671
+ "type": "opencollective",
3672
+ "url": "https://opencollective.com/unified"
3673
+ }
3674
+ },
3675
+ "node_modules/mdast-util-to-hast": {
3676
+ "version": "13.2.0",
3677
+ "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz",
3678
+ "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==",
3679
+ "license": "MIT",
3680
+ "dependencies": {
3681
+ "@types/hast": "^3.0.0",
3682
+ "@types/mdast": "^4.0.0",
3683
+ "@ungap/structured-clone": "^1.0.0",
3684
+ "devlop": "^1.0.0",
3685
+ "micromark-util-sanitize-uri": "^2.0.0",
3686
+ "trim-lines": "^3.0.0",
3687
+ "unist-util-position": "^5.0.0",
3688
+ "unist-util-visit": "^5.0.0",
3689
+ "vfile": "^6.0.0"
3690
+ },
3691
+ "funding": {
3692
+ "type": "opencollective",
3693
+ "url": "https://opencollective.com/unified"
3694
+ }
3695
+ },
3696
+ "node_modules/mdast-util-to-markdown": {
3697
+ "version": "2.1.2",
3698
+ "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz",
3699
+ "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==",
3700
+ "license": "MIT",
3701
+ "dependencies": {
3702
+ "@types/mdast": "^4.0.0",
3703
+ "@types/unist": "^3.0.0",
3704
+ "longest-streak": "^3.0.0",
3705
+ "mdast-util-phrasing": "^4.0.0",
3706
+ "mdast-util-to-string": "^4.0.0",
3707
+ "micromark-util-classify-character": "^2.0.0",
3708
+ "micromark-util-decode-string": "^2.0.0",
3709
+ "unist-util-visit": "^5.0.0",
3710
+ "zwitch": "^2.0.0"
3711
+ },
3712
+ "funding": {
3713
+ "type": "opencollective",
3714
+ "url": "https://opencollective.com/unified"
3715
+ }
3716
+ },
3717
+ "node_modules/mdast-util-to-string": {
3718
+ "version": "4.0.0",
3719
+ "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz",
3720
+ "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==",
3721
+ "license": "MIT",
3722
+ "dependencies": {
3723
+ "@types/mdast": "^4.0.0"
3724
+ },
3725
+ "funding": {
3726
+ "type": "opencollective",
3727
+ "url": "https://opencollective.com/unified"
3728
+ }
3729
+ },
3730
+ "node_modules/merge-refs": {
3731
+ "version": "2.0.0",
3732
+ "resolved": "https://registry.npmjs.org/merge-refs/-/merge-refs-2.0.0.tgz",
3733
+ "integrity": "sha512-3+B21mYK2IqUWnd2EivABLT7ueDhb0b8/dGK8LoFQPrU61YITeCMn14F7y7qZafWNZhUEKb24cJdiT5Wxs3prg==",
3734
+ "license": "MIT",
3735
+ "funding": {
3736
+ "url": "https://github.com/wojtekmaj/merge-refs?sponsor=1"
3737
+ },
3738
+ "peerDependencies": {
3739
+ "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
3740
+ },
3741
+ "peerDependenciesMeta": {
3742
+ "@types/react": {
3743
+ "optional": true
3744
+ }
3745
+ }
3746
+ },
3747
+ "node_modules/micromark": {
3748
+ "version": "4.0.2",
3749
+ "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz",
3750
+ "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==",
3751
+ "funding": [
3752
+ {
3753
+ "type": "GitHub Sponsors",
3754
+ "url": "https://github.com/sponsors/unifiedjs"
3755
+ },
3756
+ {
3757
+ "type": "OpenCollective",
3758
+ "url": "https://opencollective.com/unified"
3759
+ }
3760
+ ],
3761
+ "license": "MIT",
3762
+ "dependencies": {
3763
+ "@types/debug": "^4.0.0",
3764
+ "debug": "^4.0.0",
3765
+ "decode-named-character-reference": "^1.0.0",
3766
+ "devlop": "^1.0.0",
3767
+ "micromark-core-commonmark": "^2.0.0",
3768
+ "micromark-factory-space": "^2.0.0",
3769
+ "micromark-util-character": "^2.0.0",
3770
+ "micromark-util-chunked": "^2.0.0",
3771
+ "micromark-util-combine-extensions": "^2.0.0",
3772
+ "micromark-util-decode-numeric-character-reference": "^2.0.0",
3773
+ "micromark-util-encode": "^2.0.0",
3774
+ "micromark-util-normalize-identifier": "^2.0.0",
3775
+ "micromark-util-resolve-all": "^2.0.0",
3776
+ "micromark-util-sanitize-uri": "^2.0.0",
3777
+ "micromark-util-subtokenize": "^2.0.0",
3778
+ "micromark-util-symbol": "^2.0.0",
3779
+ "micromark-util-types": "^2.0.0"
3780
+ }
3781
+ },
3782
+ "node_modules/micromark-core-commonmark": {
3783
+ "version": "2.0.3",
3784
+ "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz",
3785
+ "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==",
3786
+ "funding": [
3787
+ {
3788
+ "type": "GitHub Sponsors",
3789
+ "url": "https://github.com/sponsors/unifiedjs"
3790
+ },
3791
+ {
3792
+ "type": "OpenCollective",
3793
+ "url": "https://opencollective.com/unified"
3794
+ }
3795
+ ],
3796
+ "license": "MIT",
3797
+ "dependencies": {
3798
+ "decode-named-character-reference": "^1.0.0",
3799
+ "devlop": "^1.0.0",
3800
+ "micromark-factory-destination": "^2.0.0",
3801
+ "micromark-factory-label": "^2.0.0",
3802
+ "micromark-factory-space": "^2.0.0",
3803
+ "micromark-factory-title": "^2.0.0",
3804
+ "micromark-factory-whitespace": "^2.0.0",
3805
+ "micromark-util-character": "^2.0.0",
3806
+ "micromark-util-chunked": "^2.0.0",
3807
+ "micromark-util-classify-character": "^2.0.0",
3808
+ "micromark-util-html-tag-name": "^2.0.0",
3809
+ "micromark-util-normalize-identifier": "^2.0.0",
3810
+ "micromark-util-resolve-all": "^2.0.0",
3811
+ "micromark-util-subtokenize": "^2.0.0",
3812
+ "micromark-util-symbol": "^2.0.0",
3813
+ "micromark-util-types": "^2.0.0"
3814
+ }
3815
+ },
3816
+ "node_modules/micromark-extension-math": {
3817
+ "version": "3.1.0",
3818
+ "resolved": "https://registry.npmjs.org/micromark-extension-math/-/micromark-extension-math-3.1.0.tgz",
3819
+ "integrity": "sha512-lvEqd+fHjATVs+2v/8kg9i5Q0AP2k85H0WUOwpIVvUML8BapsMvh1XAogmQjOCsLpoKRCVQqEkQBB3NhVBcsOg==",
3820
+ "license": "MIT",
3821
+ "dependencies": {
3822
+ "@types/katex": "^0.16.0",
3823
+ "devlop": "^1.0.0",
3824
+ "katex": "^0.16.0",
3825
+ "micromark-factory-space": "^2.0.0",
3826
+ "micromark-util-character": "^2.0.0",
3827
+ "micromark-util-symbol": "^2.0.0",
3828
+ "micromark-util-types": "^2.0.0"
3829
+ },
3830
+ "funding": {
3831
+ "type": "opencollective",
3832
+ "url": "https://opencollective.com/unified"
3833
+ }
3834
+ },
3835
+ "node_modules/micromark-factory-destination": {
3836
+ "version": "2.0.1",
3837
+ "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz",
3838
+ "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==",
3839
+ "funding": [
3840
+ {
3841
+ "type": "GitHub Sponsors",
3842
+ "url": "https://github.com/sponsors/unifiedjs"
3843
+ },
3844
+ {
3845
+ "type": "OpenCollective",
3846
+ "url": "https://opencollective.com/unified"
3847
+ }
3848
+ ],
3849
+ "license": "MIT",
3850
+ "dependencies": {
3851
+ "micromark-util-character": "^2.0.0",
3852
+ "micromark-util-symbol": "^2.0.0",
3853
+ "micromark-util-types": "^2.0.0"
3854
+ }
3855
+ },
3856
+ "node_modules/micromark-factory-label": {
3857
+ "version": "2.0.1",
3858
+ "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz",
3859
+ "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==",
3860
+ "funding": [
3861
+ {
3862
+ "type": "GitHub Sponsors",
3863
+ "url": "https://github.com/sponsors/unifiedjs"
3864
+ },
3865
+ {
3866
+ "type": "OpenCollective",
3867
+ "url": "https://opencollective.com/unified"
3868
+ }
3869
+ ],
3870
+ "license": "MIT",
3871
+ "dependencies": {
3872
+ "devlop": "^1.0.0",
3873
+ "micromark-util-character": "^2.0.0",
3874
+ "micromark-util-symbol": "^2.0.0",
3875
+ "micromark-util-types": "^2.0.0"
3876
+ }
3877
+ },
3878
+ "node_modules/micromark-factory-space": {
3879
+ "version": "2.0.1",
3880
+ "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz",
3881
+ "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==",
3882
+ "funding": [
3883
+ {
3884
+ "type": "GitHub Sponsors",
3885
+ "url": "https://github.com/sponsors/unifiedjs"
3886
+ },
3887
+ {
3888
+ "type": "OpenCollective",
3889
+ "url": "https://opencollective.com/unified"
3890
+ }
3891
+ ],
3892
+ "license": "MIT",
3893
+ "dependencies": {
3894
+ "micromark-util-character": "^2.0.0",
3895
+ "micromark-util-types": "^2.0.0"
3896
+ }
3897
+ },
3898
+ "node_modules/micromark-factory-title": {
3899
+ "version": "2.0.1",
3900
+ "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz",
3901
+ "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==",
3902
+ "funding": [
3903
+ {
3904
+ "type": "GitHub Sponsors",
3905
+ "url": "https://github.com/sponsors/unifiedjs"
3906
+ },
3907
+ {
3908
+ "type": "OpenCollective",
3909
+ "url": "https://opencollective.com/unified"
3910
+ }
3911
+ ],
3912
+ "license": "MIT",
3913
+ "dependencies": {
3914
+ "micromark-factory-space": "^2.0.0",
3915
+ "micromark-util-character": "^2.0.0",
3916
+ "micromark-util-symbol": "^2.0.0",
3917
+ "micromark-util-types": "^2.0.0"
3918
+ }
3919
+ },
3920
+ "node_modules/micromark-factory-whitespace": {
3921
+ "version": "2.0.1",
3922
+ "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz",
3923
+ "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==",
3924
+ "funding": [
3925
+ {
3926
+ "type": "GitHub Sponsors",
3927
+ "url": "https://github.com/sponsors/unifiedjs"
3928
+ },
3929
+ {
3930
+ "type": "OpenCollective",
3931
+ "url": "https://opencollective.com/unified"
3932
+ }
3933
+ ],
3934
+ "license": "MIT",
3935
+ "dependencies": {
3936
+ "micromark-factory-space": "^2.0.0",
3937
+ "micromark-util-character": "^2.0.0",
3938
+ "micromark-util-symbol": "^2.0.0",
3939
+ "micromark-util-types": "^2.0.0"
3940
+ }
3941
+ },
3942
+ "node_modules/micromark-util-character": {
3943
+ "version": "2.1.1",
3944
+ "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz",
3945
+ "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==",
3946
+ "funding": [
3947
+ {
3948
+ "type": "GitHub Sponsors",
3949
+ "url": "https://github.com/sponsors/unifiedjs"
3950
+ },
3951
+ {
3952
+ "type": "OpenCollective",
3953
+ "url": "https://opencollective.com/unified"
3954
+ }
3955
+ ],
3956
+ "license": "MIT",
3957
+ "dependencies": {
3958
+ "micromark-util-symbol": "^2.0.0",
3959
+ "micromark-util-types": "^2.0.0"
3960
+ }
3961
+ },
3962
+ "node_modules/micromark-util-chunked": {
3963
+ "version": "2.0.1",
3964
+ "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz",
3965
+ "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==",
3966
+ "funding": [
3967
+ {
3968
+ "type": "GitHub Sponsors",
3969
+ "url": "https://github.com/sponsors/unifiedjs"
3970
+ },
3971
+ {
3972
+ "type": "OpenCollective",
3973
+ "url": "https://opencollective.com/unified"
3974
+ }
3975
+ ],
3976
+ "license": "MIT",
3977
+ "dependencies": {
3978
+ "micromark-util-symbol": "^2.0.0"
3979
+ }
3980
+ },
3981
+ "node_modules/micromark-util-classify-character": {
3982
+ "version": "2.0.1",
3983
+ "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz",
3984
+ "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==",
3985
+ "funding": [
3986
+ {
3987
+ "type": "GitHub Sponsors",
3988
+ "url": "https://github.com/sponsors/unifiedjs"
3989
+ },
3990
+ {
3991
+ "type": "OpenCollective",
3992
+ "url": "https://opencollective.com/unified"
3993
+ }
3994
+ ],
3995
+ "license": "MIT",
3996
+ "dependencies": {
3997
+ "micromark-util-character": "^2.0.0",
3998
+ "micromark-util-symbol": "^2.0.0",
3999
+ "micromark-util-types": "^2.0.0"
4000
+ }
4001
+ },
4002
+ "node_modules/micromark-util-combine-extensions": {
4003
+ "version": "2.0.1",
4004
+ "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz",
4005
+ "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==",
4006
+ "funding": [
4007
+ {
4008
+ "type": "GitHub Sponsors",
4009
+ "url": "https://github.com/sponsors/unifiedjs"
4010
+ },
4011
+ {
4012
+ "type": "OpenCollective",
4013
+ "url": "https://opencollective.com/unified"
4014
+ }
4015
+ ],
4016
+ "license": "MIT",
4017
+ "dependencies": {
4018
+ "micromark-util-chunked": "^2.0.0",
4019
+ "micromark-util-types": "^2.0.0"
4020
+ }
4021
+ },
4022
+ "node_modules/micromark-util-decode-numeric-character-reference": {
4023
+ "version": "2.0.2",
4024
+ "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz",
4025
+ "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==",
4026
+ "funding": [
4027
+ {
4028
+ "type": "GitHub Sponsors",
4029
+ "url": "https://github.com/sponsors/unifiedjs"
4030
+ },
4031
+ {
4032
+ "type": "OpenCollective",
4033
+ "url": "https://opencollective.com/unified"
4034
+ }
4035
+ ],
4036
+ "license": "MIT",
4037
+ "dependencies": {
4038
+ "micromark-util-symbol": "^2.0.0"
4039
+ }
4040
+ },
4041
+ "node_modules/micromark-util-decode-string": {
4042
+ "version": "2.0.1",
4043
+ "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz",
4044
+ "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==",
4045
+ "funding": [
4046
+ {
4047
+ "type": "GitHub Sponsors",
4048
+ "url": "https://github.com/sponsors/unifiedjs"
4049
+ },
4050
+ {
4051
+ "type": "OpenCollective",
4052
+ "url": "https://opencollective.com/unified"
4053
+ }
4054
+ ],
4055
+ "license": "MIT",
4056
+ "dependencies": {
4057
+ "decode-named-character-reference": "^1.0.0",
4058
+ "micromark-util-character": "^2.0.0",
4059
+ "micromark-util-decode-numeric-character-reference": "^2.0.0",
4060
+ "micromark-util-symbol": "^2.0.0"
4061
+ }
4062
+ },
4063
+ "node_modules/micromark-util-encode": {
4064
+ "version": "2.0.1",
4065
+ "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz",
4066
+ "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==",
4067
+ "funding": [
4068
+ {
4069
+ "type": "GitHub Sponsors",
4070
+ "url": "https://github.com/sponsors/unifiedjs"
4071
+ },
4072
+ {
4073
+ "type": "OpenCollective",
4074
+ "url": "https://opencollective.com/unified"
4075
+ }
4076
+ ],
4077
+ "license": "MIT"
4078
+ },
4079
+ "node_modules/micromark-util-html-tag-name": {
4080
+ "version": "2.0.1",
4081
+ "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz",
4082
+ "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==",
4083
+ "funding": [
4084
+ {
4085
+ "type": "GitHub Sponsors",
4086
+ "url": "https://github.com/sponsors/unifiedjs"
4087
+ },
4088
+ {
4089
+ "type": "OpenCollective",
4090
+ "url": "https://opencollective.com/unified"
4091
+ }
4092
+ ],
4093
+ "license": "MIT"
4094
+ },
4095
+ "node_modules/micromark-util-normalize-identifier": {
4096
+ "version": "2.0.1",
4097
+ "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz",
4098
+ "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==",
4099
+ "funding": [
4100
+ {
4101
+ "type": "GitHub Sponsors",
4102
+ "url": "https://github.com/sponsors/unifiedjs"
4103
+ },
4104
+ {
4105
+ "type": "OpenCollective",
4106
+ "url": "https://opencollective.com/unified"
4107
+ }
4108
+ ],
4109
+ "license": "MIT",
4110
+ "dependencies": {
4111
+ "micromark-util-symbol": "^2.0.0"
4112
+ }
4113
+ },
4114
+ "node_modules/micromark-util-resolve-all": {
4115
+ "version": "2.0.1",
4116
+ "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz",
4117
+ "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==",
4118
+ "funding": [
4119
+ {
4120
+ "type": "GitHub Sponsors",
4121
+ "url": "https://github.com/sponsors/unifiedjs"
4122
+ },
4123
+ {
4124
+ "type": "OpenCollective",
4125
+ "url": "https://opencollective.com/unified"
4126
+ }
4127
+ ],
4128
+ "license": "MIT",
4129
+ "dependencies": {
4130
+ "micromark-util-types": "^2.0.0"
4131
+ }
4132
+ },
4133
+ "node_modules/micromark-util-sanitize-uri": {
4134
+ "version": "2.0.1",
4135
+ "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz",
4136
+ "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==",
4137
+ "funding": [
4138
+ {
4139
+ "type": "GitHub Sponsors",
4140
+ "url": "https://github.com/sponsors/unifiedjs"
4141
+ },
4142
+ {
4143
+ "type": "OpenCollective",
4144
+ "url": "https://opencollective.com/unified"
4145
+ }
4146
+ ],
4147
+ "license": "MIT",
4148
+ "dependencies": {
4149
+ "micromark-util-character": "^2.0.0",
4150
+ "micromark-util-encode": "^2.0.0",
4151
+ "micromark-util-symbol": "^2.0.0"
4152
+ }
4153
+ },
4154
+ "node_modules/micromark-util-subtokenize": {
4155
+ "version": "2.1.0",
4156
+ "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz",
4157
+ "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==",
4158
+ "funding": [
4159
+ {
4160
+ "type": "GitHub Sponsors",
4161
+ "url": "https://github.com/sponsors/unifiedjs"
4162
+ },
4163
+ {
4164
+ "type": "OpenCollective",
4165
+ "url": "https://opencollective.com/unified"
4166
+ }
4167
+ ],
4168
+ "license": "MIT",
4169
+ "dependencies": {
4170
+ "devlop": "^1.0.0",
4171
+ "micromark-util-chunked": "^2.0.0",
4172
+ "micromark-util-symbol": "^2.0.0",
4173
+ "micromark-util-types": "^2.0.0"
4174
+ }
4175
+ },
4176
+ "node_modules/micromark-util-symbol": {
4177
+ "version": "2.0.1",
4178
+ "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz",
4179
+ "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==",
4180
+ "funding": [
4181
+ {
4182
+ "type": "GitHub Sponsors",
4183
+ "url": "https://github.com/sponsors/unifiedjs"
4184
+ },
4185
+ {
4186
+ "type": "OpenCollective",
4187
+ "url": "https://opencollective.com/unified"
4188
+ }
4189
+ ],
4190
+ "license": "MIT"
4191
+ },
4192
+ "node_modules/micromark-util-types": {
4193
+ "version": "2.0.2",
4194
+ "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz",
4195
+ "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==",
4196
+ "funding": [
4197
+ {
4198
+ "type": "GitHub Sponsors",
4199
+ "url": "https://github.com/sponsors/unifiedjs"
4200
+ },
4201
+ {
4202
+ "type": "OpenCollective",
4203
+ "url": "https://opencollective.com/unified"
4204
+ }
4205
+ ],
4206
+ "license": "MIT"
4207
+ },
4208
+ "node_modules/minimatch": {
4209
+ "version": "3.1.2",
4210
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
4211
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
4212
+ "dev": true,
4213
  "license": "ISC",
4214
  "dependencies": {
4215
  "brace-expansion": "^1.1.7"
 
4258
  "version": "2.1.3",
4259
  "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
4260
  "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
 
4261
  "license": "MIT"
4262
  },
4263
  "node_modules/nanoid": {
 
4300
  "node": ">=0.10.0"
4301
  }
4302
  },
4303
+ "node_modules/object-assign": {
4304
+ "version": "4.1.1",
4305
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
4306
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
4307
+ "license": "MIT",
4308
+ "peer": true,
4309
+ "engines": {
4310
+ "node": ">=0.10.0"
4311
+ }
4312
+ },
4313
  "node_modules/optionator": {
4314
  "version": "0.9.4",
4315
  "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
 
4373
  "node": ">=6"
4374
  }
4375
  },
4376
+ "node_modules/parse-entities": {
4377
+ "version": "4.0.2",
4378
+ "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz",
4379
+ "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==",
4380
+ "license": "MIT",
4381
+ "dependencies": {
4382
+ "@types/unist": "^2.0.0",
4383
+ "character-entities-legacy": "^3.0.0",
4384
+ "character-reference-invalid": "^2.0.0",
4385
+ "decode-named-character-reference": "^1.0.0",
4386
+ "is-alphanumerical": "^2.0.0",
4387
+ "is-decimal": "^2.0.0",
4388
+ "is-hexadecimal": "^2.0.0"
4389
+ },
4390
+ "funding": {
4391
+ "type": "github",
4392
+ "url": "https://github.com/sponsors/wooorm"
4393
+ }
4394
+ },
4395
+ "node_modules/parse-entities/node_modules/@types/unist": {
4396
+ "version": "2.0.11",
4397
+ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz",
4398
+ "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==",
4399
+ "license": "MIT"
4400
+ },
4401
+ "node_modules/parse5": {
4402
+ "version": "7.3.0",
4403
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
4404
+ "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==",
4405
+ "license": "MIT",
4406
+ "dependencies": {
4407
+ "entities": "^6.0.0"
4408
+ },
4409
+ "funding": {
4410
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
4411
+ }
4412
+ },
4413
  "node_modules/path-exists": {
4414
  "version": "4.0.0",
4415
  "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
 
4505
  "node": ">= 0.8.0"
4506
  }
4507
  },
4508
+ "node_modules/prop-types": {
4509
+ "version": "15.8.1",
4510
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
4511
+ "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
4512
+ "license": "MIT",
4513
+ "peer": true,
4514
+ "dependencies": {
4515
+ "loose-envify": "^1.4.0",
4516
+ "object-assign": "^4.1.1",
4517
+ "react-is": "^16.13.1"
4518
+ }
4519
+ },
4520
+ "node_modules/property-information": {
4521
+ "version": "7.1.0",
4522
+ "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz",
4523
+ "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==",
4524
+ "license": "MIT",
4525
+ "funding": {
4526
+ "type": "github",
4527
+ "url": "https://github.com/sponsors/wooorm"
4528
+ }
4529
+ },
4530
  "node_modules/punycode": {
4531
  "version": "2.3.1",
4532
  "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
 
4562
  "react": "^18.3.1"
4563
  }
4564
  },
4565
+ "node_modules/react-is": {
4566
+ "version": "16.13.1",
4567
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
4568
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
4569
+ "license": "MIT",
4570
+ "peer": true
4571
+ },
4572
+ "node_modules/react-katex": {
4573
+ "version": "3.1.0",
4574
+ "resolved": "https://registry.npmjs.org/react-katex/-/react-katex-3.1.0.tgz",
4575
+ "integrity": "sha512-At9uLOkC75gwn2N+ZXc5HD8TlATsB+3Hkp9OGs6uA8tM3dwZ3Wljn74Bk3JyHFPgSnesY/EMrIAB1WJwqZqejA==",
4576
+ "license": "MIT",
4577
+ "dependencies": {
4578
+ "katex": "^0.16.0"
4579
+ },
4580
+ "peerDependencies": {
4581
+ "prop-types": "^15.8.1",
4582
+ "react": ">=15.3.2 <20"
4583
+ }
4584
+ },
4585
+ "node_modules/react-markdown": {
4586
+ "version": "10.1.0",
4587
+ "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz",
4588
+ "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==",
4589
+ "license": "MIT",
4590
+ "dependencies": {
4591
+ "@types/hast": "^3.0.0",
4592
+ "@types/mdast": "^4.0.0",
4593
+ "devlop": "^1.0.0",
4594
+ "hast-util-to-jsx-runtime": "^2.0.0",
4595
+ "html-url-attributes": "^3.0.0",
4596
+ "mdast-util-to-hast": "^13.0.0",
4597
+ "remark-parse": "^11.0.0",
4598
+ "remark-rehype": "^11.0.0",
4599
+ "unified": "^11.0.0",
4600
+ "unist-util-visit": "^5.0.0",
4601
+ "vfile": "^6.0.0"
4602
+ },
4603
+ "funding": {
4604
+ "type": "opencollective",
4605
+ "url": "https://opencollective.com/unified"
4606
+ },
4607
+ "peerDependencies": {
4608
+ "@types/react": ">=18",
4609
+ "react": ">=18"
4610
+ }
4611
+ },
4612
  "node_modules/react-pdf": {
4613
  "version": "10.0.1",
4614
  "resolved": "https://registry.npmjs.org/react-pdf/-/react-pdf-10.0.1.tgz",
 
4686
  "react-dom": ">=18"
4687
  }
4688
  },
4689
+ "node_modules/rehype-katex": {
4690
+ "version": "7.0.1",
4691
+ "resolved": "https://registry.npmjs.org/rehype-katex/-/rehype-katex-7.0.1.tgz",
4692
+ "integrity": "sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==",
4693
+ "license": "MIT",
4694
+ "dependencies": {
4695
+ "@types/hast": "^3.0.0",
4696
+ "@types/katex": "^0.16.0",
4697
+ "hast-util-from-html-isomorphic": "^2.0.0",
4698
+ "hast-util-to-text": "^4.0.0",
4699
+ "katex": "^0.16.0",
4700
+ "unist-util-visit-parents": "^6.0.0",
4701
+ "vfile": "^6.0.0"
4702
+ },
4703
+ "funding": {
4704
+ "type": "opencollective",
4705
+ "url": "https://opencollective.com/unified"
4706
+ }
4707
+ },
4708
+ "node_modules/remark-math": {
4709
+ "version": "6.0.0",
4710
+ "resolved": "https://registry.npmjs.org/remark-math/-/remark-math-6.0.0.tgz",
4711
+ "integrity": "sha512-MMqgnP74Igy+S3WwnhQ7kqGlEerTETXMvJhrUzDikVZ2/uogJCb+WHUg97hK9/jcfc0dkD73s3LN8zU49cTEtA==",
4712
+ "license": "MIT",
4713
+ "dependencies": {
4714
+ "@types/mdast": "^4.0.0",
4715
+ "mdast-util-math": "^3.0.0",
4716
+ "micromark-extension-math": "^3.0.0",
4717
+ "unified": "^11.0.0"
4718
+ },
4719
+ "funding": {
4720
+ "type": "opencollective",
4721
+ "url": "https://opencollective.com/unified"
4722
+ }
4723
+ },
4724
+ "node_modules/remark-parse": {
4725
+ "version": "11.0.0",
4726
+ "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz",
4727
+ "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==",
4728
+ "license": "MIT",
4729
+ "dependencies": {
4730
+ "@types/mdast": "^4.0.0",
4731
+ "mdast-util-from-markdown": "^2.0.0",
4732
+ "micromark-util-types": "^2.0.0",
4733
+ "unified": "^11.0.0"
4734
+ },
4735
+ "funding": {
4736
+ "type": "opencollective",
4737
+ "url": "https://opencollective.com/unified"
4738
+ }
4739
+ },
4740
+ "node_modules/remark-rehype": {
4741
+ "version": "11.1.2",
4742
+ "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz",
4743
+ "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==",
4744
+ "license": "MIT",
4745
+ "dependencies": {
4746
+ "@types/hast": "^3.0.0",
4747
+ "@types/mdast": "^4.0.0",
4748
+ "mdast-util-to-hast": "^13.0.0",
4749
+ "unified": "^11.0.0",
4750
+ "vfile": "^6.0.0"
4751
+ },
4752
+ "funding": {
4753
+ "type": "opencollective",
4754
+ "url": "https://opencollective.com/unified"
4755
+ }
4756
+ },
4757
  "node_modules/resolve-from": {
4758
  "version": "4.0.0",
4759
  "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
 
4861
  "node": ">=0.10.0"
4862
  }
4863
  },
4864
+ "node_modules/space-separated-tokens": {
4865
+ "version": "2.0.2",
4866
+ "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz",
4867
+ "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==",
4868
+ "license": "MIT",
4869
+ "funding": {
4870
+ "type": "github",
4871
+ "url": "https://github.com/sponsors/wooorm"
4872
+ }
4873
+ },
4874
+ "node_modules/stringify-entities": {
4875
+ "version": "4.0.4",
4876
+ "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz",
4877
+ "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==",
4878
+ "license": "MIT",
4879
+ "dependencies": {
4880
+ "character-entities-html4": "^2.0.0",
4881
+ "character-entities-legacy": "^3.0.0"
4882
+ },
4883
+ "funding": {
4884
+ "type": "github",
4885
+ "url": "https://github.com/sponsors/wooorm"
4886
+ }
4887
+ },
4888
  "node_modules/strip-json-comments": {
4889
  "version": "3.1.1",
4890
  "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
 
4898
  "url": "https://github.com/sponsors/sindresorhus"
4899
  }
4900
  },
4901
+ "node_modules/style-to-js": {
4902
+ "version": "1.1.17",
4903
+ "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.17.tgz",
4904
+ "integrity": "sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA==",
4905
+ "license": "MIT",
4906
+ "dependencies": {
4907
+ "style-to-object": "1.0.9"
4908
+ }
4909
+ },
4910
+ "node_modules/style-to-object": {
4911
+ "version": "1.0.9",
4912
+ "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.9.tgz",
4913
+ "integrity": "sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==",
4914
+ "license": "MIT",
4915
+ "dependencies": {
4916
+ "inline-style-parser": "0.2.4"
4917
+ }
4918
+ },
4919
  "node_modules/supports-color": {
4920
  "version": "7.2.0",
4921
  "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
 
4993
  "url": "https://github.com/sponsors/SuperchupuDev"
4994
  }
4995
  },
4996
+ "node_modules/trim-lines": {
4997
+ "version": "3.0.1",
4998
+ "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz",
4999
+ "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==",
5000
+ "license": "MIT",
5001
+ "funding": {
5002
+ "type": "github",
5003
+ "url": "https://github.com/sponsors/wooorm"
5004
+ }
5005
+ },
5006
+ "node_modules/trough": {
5007
+ "version": "2.2.0",
5008
+ "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz",
5009
+ "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==",
5010
+ "license": "MIT",
5011
+ "funding": {
5012
+ "type": "github",
5013
+ "url": "https://github.com/sponsors/wooorm"
5014
+ }
5015
+ },
5016
  "node_modules/type-check": {
5017
  "version": "0.4.0",
5018
  "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
 
5026
  "node": ">= 0.8.0"
5027
  }
5028
  },
5029
+ "node_modules/unified": {
5030
+ "version": "11.0.5",
5031
+ "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz",
5032
+ "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==",
5033
+ "license": "MIT",
5034
+ "dependencies": {
5035
+ "@types/unist": "^3.0.0",
5036
+ "bail": "^2.0.0",
5037
+ "devlop": "^1.0.0",
5038
+ "extend": "^3.0.0",
5039
+ "is-plain-obj": "^4.0.0",
5040
+ "trough": "^2.0.0",
5041
+ "vfile": "^6.0.0"
5042
+ },
5043
+ "funding": {
5044
+ "type": "opencollective",
5045
+ "url": "https://opencollective.com/unified"
5046
+ }
5047
+ },
5048
+ "node_modules/unist-util-find-after": {
5049
+ "version": "5.0.0",
5050
+ "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-5.0.0.tgz",
5051
+ "integrity": "sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==",
5052
+ "license": "MIT",
5053
+ "dependencies": {
5054
+ "@types/unist": "^3.0.0",
5055
+ "unist-util-is": "^6.0.0"
5056
+ },
5057
+ "funding": {
5058
+ "type": "opencollective",
5059
+ "url": "https://opencollective.com/unified"
5060
+ }
5061
+ },
5062
+ "node_modules/unist-util-is": {
5063
+ "version": "6.0.0",
5064
+ "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz",
5065
+ "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==",
5066
+ "license": "MIT",
5067
+ "dependencies": {
5068
+ "@types/unist": "^3.0.0"
5069
+ },
5070
+ "funding": {
5071
+ "type": "opencollective",
5072
+ "url": "https://opencollective.com/unified"
5073
+ }
5074
+ },
5075
+ "node_modules/unist-util-position": {
5076
+ "version": "5.0.0",
5077
+ "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz",
5078
+ "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==",
5079
+ "license": "MIT",
5080
+ "dependencies": {
5081
+ "@types/unist": "^3.0.0"
5082
+ },
5083
+ "funding": {
5084
+ "type": "opencollective",
5085
+ "url": "https://opencollective.com/unified"
5086
+ }
5087
+ },
5088
+ "node_modules/unist-util-remove-position": {
5089
+ "version": "5.0.0",
5090
+ "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz",
5091
+ "integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==",
5092
+ "license": "MIT",
5093
+ "dependencies": {
5094
+ "@types/unist": "^3.0.0",
5095
+ "unist-util-visit": "^5.0.0"
5096
+ },
5097
+ "funding": {
5098
+ "type": "opencollective",
5099
+ "url": "https://opencollective.com/unified"
5100
+ }
5101
+ },
5102
+ "node_modules/unist-util-stringify-position": {
5103
+ "version": "4.0.0",
5104
+ "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz",
5105
+ "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==",
5106
+ "license": "MIT",
5107
+ "dependencies": {
5108
+ "@types/unist": "^3.0.0"
5109
+ },
5110
+ "funding": {
5111
+ "type": "opencollective",
5112
+ "url": "https://opencollective.com/unified"
5113
+ }
5114
+ },
5115
+ "node_modules/unist-util-visit": {
5116
+ "version": "5.0.0",
5117
+ "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz",
5118
+ "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==",
5119
+ "license": "MIT",
5120
+ "dependencies": {
5121
+ "@types/unist": "^3.0.0",
5122
+ "unist-util-is": "^6.0.0",
5123
+ "unist-util-visit-parents": "^6.0.0"
5124
+ },
5125
+ "funding": {
5126
+ "type": "opencollective",
5127
+ "url": "https://opencollective.com/unified"
5128
+ }
5129
+ },
5130
+ "node_modules/unist-util-visit-parents": {
5131
+ "version": "6.0.1",
5132
+ "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz",
5133
+ "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==",
5134
+ "license": "MIT",
5135
+ "dependencies": {
5136
+ "@types/unist": "^3.0.0",
5137
+ "unist-util-is": "^6.0.0"
5138
+ },
5139
+ "funding": {
5140
+ "type": "opencollective",
5141
+ "url": "https://opencollective.com/unified"
5142
+ }
5143
+ },
5144
  "node_modules/update-browserslist-db": {
5145
  "version": "1.1.3",
5146
  "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
 
5181
  "punycode": "^2.1.0"
5182
  }
5183
  },
5184
+ "node_modules/vfile": {
5185
+ "version": "6.0.3",
5186
+ "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz",
5187
+ "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==",
5188
+ "license": "MIT",
5189
+ "dependencies": {
5190
+ "@types/unist": "^3.0.0",
5191
+ "vfile-message": "^4.0.0"
5192
+ },
5193
+ "funding": {
5194
+ "type": "opencollective",
5195
+ "url": "https://opencollective.com/unified"
5196
+ }
5197
+ },
5198
+ "node_modules/vfile-location": {
5199
+ "version": "5.0.3",
5200
+ "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz",
5201
+ "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==",
5202
+ "license": "MIT",
5203
+ "dependencies": {
5204
+ "@types/unist": "^3.0.0",
5205
+ "vfile": "^6.0.0"
5206
+ },
5207
+ "funding": {
5208
+ "type": "opencollective",
5209
+ "url": "https://opencollective.com/unified"
5210
+ }
5211
+ },
5212
+ "node_modules/vfile-message": {
5213
+ "version": "4.0.3",
5214
+ "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz",
5215
+ "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==",
5216
+ "license": "MIT",
5217
+ "dependencies": {
5218
+ "@types/unist": "^3.0.0",
5219
+ "unist-util-stringify-position": "^4.0.0"
5220
+ },
5221
+ "funding": {
5222
+ "type": "opencollective",
5223
+ "url": "https://opencollective.com/unified"
5224
+ }
5225
+ },
5226
  "node_modules/vite": {
5227
  "version": "7.0.6",
5228
  "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.6.tgz",
 
5307
  "loose-envify": "^1.0.0"
5308
  }
5309
  },
5310
+ "node_modules/web-namespaces": {
5311
+ "version": "2.0.1",
5312
+ "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz",
5313
+ "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==",
5314
+ "license": "MIT",
5315
+ "funding": {
5316
+ "type": "github",
5317
+ "url": "https://github.com/sponsors/wooorm"
5318
+ }
5319
+ },
5320
  "node_modules/which": {
5321
  "version": "2.0.2",
5322
  "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
 
5362
  "funding": {
5363
  "url": "https://github.com/sponsors/sindresorhus"
5364
  }
5365
+ },
5366
+ "node_modules/zwitch": {
5367
+ "version": "2.0.4",
5368
+ "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz",
5369
+ "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==",
5370
+ "license": "MIT",
5371
+ "funding": {
5372
+ "type": "github",
5373
+ "url": "https://github.com/sponsors/wooorm"
5374
+ }
5375
  }
5376
  }
5377
  }
frontend/package.json CHANGED
@@ -12,11 +12,16 @@
12
  "dependencies": {
13
  "@tailwindcss/postcss": "^4.1.11",
14
  "autoprefixer": "^10.4.21",
 
15
  "postcss": "^8.5.6",
16
  "react": "^18.3.1",
17
  "react-dom": "^18.3.1",
 
 
18
  "react-pdf": "^10.0.1",
19
  "react-router-dom": "^7.7.0",
 
 
20
  "tailwindcss": "^4.1.11"
21
  },
22
  "devDependencies": {
 
12
  "dependencies": {
13
  "@tailwindcss/postcss": "^4.1.11",
14
  "autoprefixer": "^10.4.21",
15
+ "katex": "^0.16.22",
16
  "postcss": "^8.5.6",
17
  "react": "^18.3.1",
18
  "react-dom": "^18.3.1",
19
+ "react-katex": "^3.1.0",
20
+ "react-markdown": "^10.1.0",
21
  "react-pdf": "^10.0.1",
22
  "react-router-dom": "^7.7.0",
23
+ "rehype-katex": "^7.0.1",
24
+ "remark-math": "^6.0.0",
25
  "tailwindcss": "^4.1.11"
26
  },
27
  "devDependencies": {
frontend/src/App.jsx CHANGED
@@ -1,6 +1,7 @@
1
  import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
2
  import Homepage from './components/Homepage';
3
  import UploadPage from './components/UploadPage';
 
4
 
5
  function App() {
6
  return (
@@ -8,6 +9,7 @@ function App() {
8
  <Routes>
9
  <Route path="/" element={<Homepage />} />
10
  <Route path="/upload" element={<UploadPage />} />
 
11
  </Routes>
12
  </Router>
13
  );
 
1
  import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
2
  import Homepage from './components/Homepage';
3
  import UploadPage from './components/UploadPage';
4
+ import DocumentProcessor from './components/DocumentProcessor';
5
 
6
  function App() {
7
  return (
 
9
  <Routes>
10
  <Route path="/" element={<Homepage />} />
11
  <Route path="/upload" element={<UploadPage />} />
12
+ <Route path="/process" element={<DocumentProcessor />} />
13
  </Routes>
14
  </Router>
15
  );
frontend/src/components/DocumentProcessor.jsx ADDED
@@ -0,0 +1,292 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useState, useRef } from 'react';
2
+ import ReactMarkdown from 'react-markdown';
3
+ import { Document, Page, pdfjs } from 'react-pdf';
4
+ import remarkMath from 'remark-math';
5
+ import rehypeKatex from 'rehype-katex';
6
+ import 'katex/dist/katex.min.css';
7
+ import 'react-pdf/dist/Page/AnnotationLayer.css';
8
+ import 'react-pdf/dist/Page/TextLayer.css';
9
+
10
+ pdfjs.GlobalWorkerOptions.workerSrc = '/pdf.worker.min.js';
11
+
12
+ function DocumentProcessor() {
13
+ const fileInputRef = useRef(null);
14
+ const [selectedFile, setSelectedFile] = useState(null);
15
+ const [processing, setProcessing] = useState(false);
16
+ const [uploadProgress, setUploadProgress] = useState(0);
17
+ const [ocrProgress, setOcrProgress] = useState(0);
18
+ const [documentData, setDocumentData] = useState(null);
19
+ const [showPdfViewer, setShowPdfViewer] = useState(false);
20
+ const [numPages, setNumPages] = useState(null);
21
+
22
+ const handleFileChange = (e) => {
23
+ setSelectedFile(e.target.files[0]);
24
+ setDocumentData(null);
25
+ setUploadProgress(0);
26
+ setOcrProgress(0);
27
+ };
28
+
29
+ const processDocument = async () => {
30
+ if (!selectedFile) return;
31
+
32
+ setProcessing(true);
33
+ setUploadProgress(0);
34
+ setOcrProgress(0);
35
+
36
+ try {
37
+ // Step 1: Upload PDF
38
+ const formData = new FormData();
39
+ formData.append('file', selectedFile);
40
+
41
+ setUploadProgress(30);
42
+ const uploadResponse = await fetch('http://localhost:8000/upload_pdf', {
43
+ method: 'POST',
44
+ body: formData,
45
+ });
46
+
47
+ if (!uploadResponse.ok) {
48
+ throw new Error('Failed to upload PDF');
49
+ }
50
+
51
+ const uploadData = await uploadResponse.json();
52
+ setUploadProgress(100);
53
+
54
+ // Step 2: Process OCR
55
+ setOcrProgress(20);
56
+ await new Promise(resolve => setTimeout(resolve, 500)); // Small delay for UX
57
+
58
+ setOcrProgress(60);
59
+ const ocrResponse = await fetch(`http://localhost:8000/process_ocr/${uploadData.file_id}`);
60
+
61
+ if (!ocrResponse.ok) {
62
+ throw new Error('Failed to process OCR');
63
+ }
64
+
65
+ const ocrData = await ocrResponse.json();
66
+ setOcrProgress(100);
67
+
68
+ // Combine all markdown from pages
69
+ const combinedMarkdown = ocrData.pages
70
+ .map(page => page.markdown)
71
+ .join('\n\n---\n\n');
72
+
73
+ setDocumentData({
74
+ fileId: uploadData.file_id,
75
+ filename: uploadData.filename,
76
+ markdown: combinedMarkdown,
77
+ pages: ocrData.pages,
78
+ totalPages: ocrData.total_pages
79
+ });
80
+
81
+ } catch (error) {
82
+ console.error('Error processing document:', error);
83
+ alert('Error processing document: ' + error.message);
84
+ } finally {
85
+ setProcessing(false);
86
+ }
87
+ };
88
+
89
+ const LoadingAnimation = () => (
90
+ <div className="flex flex-col items-center justify-center min-h-screen bg-gray-50">
91
+ <div className="text-center max-w-md">
92
+ <div className="mb-8">
93
+ <div className="w-16 h-16 border-4 border-blue-500 border-t-transparent rounded-full animate-spin mx-auto mb-4"></div>
94
+ <h2 className="text-2xl font-bold text-gray-900 mb-2">Processing Your Document</h2>
95
+ <p className="text-gray-600">This may take a moment...</p>
96
+ </div>
97
+
98
+ {/* Upload Progress */}
99
+ <div className="mb-6">
100
+ <div className="flex justify-between text-sm text-gray-600 mb-1">
101
+ <span>Uploading PDF</span>
102
+ <span>{uploadProgress}%</span>
103
+ </div>
104
+ <div className="w-full bg-gray-200 rounded-full h-2">
105
+ <div
106
+ className="bg-blue-500 h-2 rounded-full transition-all duration-300"
107
+ style={{ width: `${uploadProgress}%` }}
108
+ ></div>
109
+ </div>
110
+ </div>
111
+
112
+ {/* OCR Progress */}
113
+ <div className="mb-6">
114
+ <div className="flex justify-between text-sm text-gray-600 mb-1">
115
+ <span>Processing with AI</span>
116
+ <span>{ocrProgress}%</span>
117
+ </div>
118
+ <div className="w-full bg-gray-200 rounded-full h-2">
119
+ <div
120
+ className="bg-green-500 h-2 rounded-full transition-all duration-300"
121
+ style={{ width: `${ocrProgress}%` }}
122
+ ></div>
123
+ </div>
124
+ </div>
125
+
126
+ <p className="text-sm text-gray-500">
127
+ Using Mistral AI to extract text and understand your document structure...
128
+ </p>
129
+ </div>
130
+ </div>
131
+ );
132
+
133
+ const PdfViewer = () => (
134
+ <div className={`fixed bottom-4 left-4 bg-white rounded-lg shadow-xl border transition-all duration-300 ${
135
+ showPdfViewer ? 'w-80 h-96' : 'w-48 h-12'
136
+ }`}>
137
+ <div className="p-3 border-b flex justify-between items-center">
138
+ <span className="text-sm font-medium text-gray-700">Original PDF</span>
139
+ <button
140
+ onClick={() => setShowPdfViewer(!showPdfViewer)}
141
+ className="text-gray-500 hover:text-gray-700"
142
+ >
143
+ {showPdfViewer ? (
144
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
145
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
146
+ </svg>
147
+ ) : (
148
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
149
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 15l7-7 7 7" />
150
+ </svg>
151
+ )}
152
+ </button>
153
+ </div>
154
+
155
+ {showPdfViewer && (
156
+ <div className="h-80 overflow-auto">
157
+ <Document
158
+ file={selectedFile}
159
+ onLoadSuccess={({ numPages }) => setNumPages(numPages)}
160
+ >
161
+ {numPages && Array.from(new Array(numPages), (_, index) => (
162
+ <div key={index + 1} className="mb-2">
163
+ <Page
164
+ pageNumber={index + 1}
165
+ width={280}
166
+ />
167
+ </div>
168
+ ))}
169
+ </Document>
170
+ </div>
171
+ )}
172
+ </div>
173
+ );
174
+
175
+ if (!selectedFile) {
176
+ return (
177
+ <div className="flex items-center justify-center min-h-screen bg-gray-50">
178
+ <div className="text-center">
179
+ <h1 className="text-4xl font-bold text-gray-900 mb-4">
180
+ SokratesAI
181
+ </h1>
182
+ <p className="text-gray-600 mb-8 text-lg">
183
+ Upload your PDF and let AI transform it into interactive lessons
184
+ </p>
185
+ <input
186
+ ref={fileInputRef}
187
+ type="file"
188
+ accept=".pdf"
189
+ className="hidden"
190
+ onChange={handleFileChange}
191
+ />
192
+ <button
193
+ onClick={() => fileInputRef.current.click()}
194
+ className="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-8 rounded-lg text-lg transition-colors"
195
+ >
196
+ Upload PDF
197
+ </button>
198
+ </div>
199
+ </div>
200
+ );
201
+ }
202
+
203
+ if (processing) {
204
+ return <LoadingAnimation />;
205
+ }
206
+
207
+ if (!documentData) {
208
+ return (
209
+ <div className="flex items-center justify-center min-h-screen bg-gray-50">
210
+ <div className="text-center">
211
+ <h1 className="text-2xl font-bold text-gray-900 mb-4">
212
+ Ready to Process: {selectedFile.name}
213
+ </h1>
214
+ <p className="text-gray-600 mb-8">
215
+ Click below to extract text and create your interactive document
216
+ </p>
217
+ <button
218
+ onClick={processDocument}
219
+ className="bg-green-600 hover:bg-green-700 text-white font-bold py-3 px-8 rounded-lg text-lg transition-colors mr-4"
220
+ >
221
+ Process Document
222
+ </button>
223
+ <button
224
+ onClick={() => setSelectedFile(null)}
225
+ className="bg-gray-500 hover:bg-gray-600 text-white font-bold py-3 px-8 rounded-lg text-lg transition-colors"
226
+ >
227
+ Choose Different File
228
+ </button>
229
+ </div>
230
+ </div>
231
+ );
232
+ }
233
+
234
+ return (
235
+ <div className="min-h-screen bg-gray-50">
236
+ {/* Header */}
237
+ <div className="bg-white shadow-sm border-b">
238
+ <div className="max-w-6xl mx-auto px-4 py-4 flex justify-between items-center">
239
+ <div>
240
+ <h1 className="text-xl font-bold text-gray-900">{documentData.filename}</h1>
241
+ <p className="text-sm text-gray-600">{documentData.totalPages} pages processed</p>
242
+ </div>
243
+ <button
244
+ onClick={() => setSelectedFile(null)}
245
+ className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg transition-colors"
246
+ >
247
+ Upload New Document
248
+ </button>
249
+ </div>
250
+ </div>
251
+
252
+ {/* Document Content */}
253
+ <div className="max-w-4xl mx-auto px-4 py-8">
254
+ <div className="bg-white rounded-lg shadow-sm border p-8">
255
+ <ReactMarkdown
256
+ remarkPlugins={[remarkMath]}
257
+ rehypePlugins={[rehypeKatex]}
258
+ className="prose prose-lg max-w-none"
259
+ components={{
260
+ h1: ({ children }) => <h1 className="text-3xl font-bold mb-6 text-gray-900">{children}</h1>,
261
+ h2: ({ children }) => <h2 className="text-2xl font-bold mb-4 text-gray-900 mt-8">{children}</h2>,
262
+ h3: ({ children }) => <h3 className="text-xl font-bold mb-3 text-gray-900 mt-6">{children}</h3>,
263
+ p: ({ children }) => <p className="mb-4 text-gray-700 leading-relaxed">{children}</p>,
264
+ hr: () => <hr className="my-8 border-gray-300" />,
265
+ ul: ({ children }) => <ul className="mb-4 ml-6 list-disc">{children}</ul>,
266
+ ol: ({ children }) => <ol className="mb-4 ml-6 list-decimal">{children}</ol>,
267
+ li: ({ children }) => <li className="mb-1 text-gray-700">{children}</li>,
268
+ blockquote: ({ children }) => (
269
+ <blockquote className="border-l-4 border-blue-500 pl-4 italic my-4 text-gray-600">
270
+ {children}
271
+ </blockquote>
272
+ ),
273
+ code: ({ inline, children }) =>
274
+ inline ?
275
+ <code className="bg-gray-100 px-1 py-0.5 rounded text-sm font-mono">{children}</code> :
276
+ <pre className="bg-gray-100 p-4 rounded-lg overflow-x-auto my-4">
277
+ <code className="text-sm font-mono">{children}</code>
278
+ </pre>
279
+ }}
280
+ >
281
+ {documentData.markdown}
282
+ </ReactMarkdown>
283
+ </div>
284
+ </div>
285
+
286
+ {/* PDF Viewer */}
287
+ <PdfViewer />
288
+ </div>
289
+ );
290
+ }
291
+
292
+ export default DocumentProcessor;
frontend/src/components/Homepage.jsx CHANGED
@@ -5,17 +5,25 @@ function Homepage() {
5
  <div className="min-h-screen bg-gray-50 flex items-center justify-center">
6
  <div className="text-center">
7
  <h1 className="text-4xl font-bold text-gray-900 mb-4">
8
- PDF Interrogation App
9
  </h1>
10
  <p className="text-lg text-gray-600 mb-8">
11
- Upload a PDF and engage in interactive learning through AI-powered Socratic questioning
12
  </p>
13
- <Link
14
- to="/upload"
15
- className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded-lg transition-colors duration-200 inline-block"
16
- >
17
- Get Started
18
- </Link>
 
 
 
 
 
 
 
 
19
  </div>
20
  </div>
21
  );
 
5
  <div className="min-h-screen bg-gray-50 flex items-center justify-center">
6
  <div className="text-center">
7
  <h1 className="text-4xl font-bold text-gray-900 mb-4">
8
+ SokratesAI
9
  </h1>
10
  <p className="text-lg text-gray-600 mb-8">
11
+ Transform your PDFs into interactive learning experiences with AI-powered document processing
12
  </p>
13
+ <div className="space-x-4">
14
+ <Link
15
+ to="/process"
16
+ className="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-6 rounded-lg transition-colors duration-200 inline-block"
17
+ >
18
+ Process Document
19
+ </Link>
20
+ <Link
21
+ to="/upload"
22
+ className="bg-gray-500 hover:bg-gray-600 text-white font-bold py-3 px-6 rounded-lg transition-colors duration-200 inline-block"
23
+ >
24
+ Legacy Upload
25
+ </Link>
26
+ </div>
27
  </div>
28
  </div>
29
  );
frontend/src/components/UploadPage.jsx CHANGED
@@ -13,6 +13,46 @@ function UploadPage() {
13
  const [currentPage, setCurrentPage] = useState(1);
14
  const [zoomLevel, setZoomLevel] = useState(1);
15
  const [visiblePages, setVisiblePages] = useState(new Set([1]));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
  // Handle scroll to update current page and track visible pages
18
  const handleScroll = () => {
@@ -92,7 +132,7 @@ function UploadPage() {
92
  type="file"
93
  accept=".pdf"
94
  className="hidden"
95
- onChange={(e) => setSelectedFile(e.target.files[0])}
96
  />
97
  <button
98
  onClick={() => fileInputRef.current.click()}
@@ -211,7 +251,21 @@ function UploadPage() {
211
 
212
  <div className="flex-1 bg-gray-100 overflow-auto">
213
  <div className="p-4">
214
- Chat will go here
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  </div>
216
  </div>
217
  </div>
 
13
  const [currentPage, setCurrentPage] = useState(1);
14
  const [zoomLevel, setZoomLevel] = useState(1);
15
  const [visiblePages, setVisiblePages] = useState(new Set([1]));
16
+ const [chunks, setChunks] = useState([]);
17
+ const [processing, setProcessing] = useState(false);
18
+
19
+ const handleFileChange = (e) => {
20
+ setSelectedFile(e.target.files[0]);
21
+ setChunks([]); // Clear previous chunks
22
+ };
23
+
24
+ const processPdf = async () => {
25
+ if (!selectedFile) return;
26
+
27
+ setProcessing(true);
28
+ const formData = new FormData();
29
+ formData.append('file', selectedFile);
30
+
31
+ try {
32
+ const response = await fetch('http://localhost:8000/upload_pdf', {
33
+ method: 'POST',
34
+ body: formData,
35
+ });
36
+
37
+ if (response.ok) {
38
+ const data = await response.json();
39
+ // Handle the new response format - create a fake chunk array for now
40
+ setChunks([{
41
+ text: `File processed: ${data.filename}`,
42
+ page_number: 1,
43
+ chunk_type: "info",
44
+ size: data.size,
45
+ has_api_key: data.has_api_key
46
+ }]);
47
+ } else {
48
+ console.error('Failed to process PDF');
49
+ }
50
+ } catch (error) {
51
+ console.error('Error processing PDF:', error);
52
+ } finally {
53
+ setProcessing(false);
54
+ }
55
+ };
56
 
57
  // Handle scroll to update current page and track visible pages
58
  const handleScroll = () => {
 
132
  type="file"
133
  accept=".pdf"
134
  className="hidden"
135
+ onChange={handleFileChange}
136
  />
137
  <button
138
  onClick={() => fileInputRef.current.click()}
 
251
 
252
  <div className="flex-1 bg-gray-100 overflow-auto">
253
  <div className="p-4">
254
+ <button
255
+ onClick={processPdf}
256
+ disabled={processing}
257
+ className="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded mb-4"
258
+ >
259
+ {processing ? 'Processing...' : 'Process PDF'}
260
+ </button>
261
+ <div>
262
+ {chunks.map((chunk, index) => (
263
+ <div key={index} className="bg-white p-4 rounded-lg shadow mb-4">
264
+ <p className="text-sm text-gray-600">Page: {chunk.page_number}, Type: {chunk.chunk_type}</p>
265
+ <p className="text-gray-800">{chunk.text}</p>
266
+ </div>
267
+ ))}
268
+ </div>
269
  </div>
270
  </div>
271
  </div>