heymenn commited on
Commit
4b1a31e
·
1 Parent(s): f3eb7a7

initial commit

Browse files
.dockerignore ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ node_modules
2
+ dist
3
+ .git
4
+ .env.local
5
+ .DS_Store
6
+ __pycache__
7
+ *.pyc
8
+ backend/__pycache__
9
+ backend/*.pyc
.gitignore ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Logs
2
+ logs
3
+ *.log
4
+ npm-debug.log*
5
+ yarn-debug.log*
6
+ yarn-error.log*
7
+ pnpm-debug.log*
8
+ lerna-debug.log*
9
+
10
+ node_modules
11
+ dist
12
+ dist-ssr
13
+ *.local
14
+
15
+ # Editor directories and files
16
+ .vscode/*
17
+ !.vscode/extensions.json
18
+ .idea
19
+ .DS_Store
20
+ *.suo
21
+ *.ntvs*
22
+ *.njsproj
23
+ *.sln
24
+ *.sw?
25
+ .claude/*
App.tsx ADDED
@@ -0,0 +1,438 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState, useCallback, useEffect } from 'react';
2
+ import { Classification, DocumentFile, Innovation, MeetingDoc } from './types';
3
+ import { backendService } from './services/backendService';
4
+ import FilterBar from './components/FilterBar';
5
+ import DocFilterBar from './components/DocFilterBar';
6
+ import StatsDashboard from './components/StatsDashboard';
7
+ import FileContentCard from './components/FileContentCard';
8
+ import InnovationCard from './components/InnovationCard';
9
+ import { LayoutDashboard, FileText, Settings, Play, CheckCircle2, CircleDashed } from 'lucide-react';
10
+ import { useLiveQuery } from 'dexie-react-hooks';
11
+
12
+ const App: React.FC = () => {
13
+ // Application State
14
+ const [files, setFiles] = useState<DocumentFile[]>([]);
15
+ const [innovations, setInnovations] = useState<Innovation[]>([]);
16
+
17
+ const [isFetchingDocs, setIsFetchingDocs] = useState(false);
18
+ const [isProcessing, setIsProcessing] = useState(false);
19
+
20
+ // Progress tracking
21
+ const [processedCount, setProcessedCount] = useState(0);
22
+ const [currentProcessingFile, setCurrentProcessingFile] = useState<string>("");
23
+
24
+ const [currentView, setCurrentView] = useState<'list' | 'dashboard'>('list');
25
+
26
+ // New state for raw docs from API
27
+ const [rawDocs, setRawDocs] = useState<MeetingDoc[]>([]);
28
+
29
+ // Pattern state
30
+ const [patterns, setPatterns] = useState<any[]>([]);
31
+ const [selectedPatternId, setSelectedPatternId] = useState<number | null>(null);
32
+ const [isAnalyzing, setIsAnalyzing] = useState(false);
33
+
34
+ // Metadata state for Backend
35
+ const [selectedWG, setSelectedWG] = useState<string>("");
36
+ const [selectedMeeting, setSelectedMeeting] = useState<string>("");
37
+
38
+ useEffect(() => {
39
+ const fetchPatterns = async () => {
40
+ const data = await backendService.getPatterns();
41
+ setPatterns(data);
42
+ if (data.length > 0) {
43
+ setSelectedPatternId(data[0].pattern_id);
44
+ }
45
+ };
46
+ fetchPatterns();
47
+ }, []);
48
+
49
+
50
+ const handleFetchDocuments = useCallback(async (wg: string, meeting: string) => {
51
+ setIsFetchingDocs(true);
52
+ setFiles([]);
53
+ setInnovations([]);
54
+ setRawDocs([]);
55
+ setProcessedCount(0);
56
+ setSelectedWG(wg);
57
+ setSelectedMeeting(meeting);
58
+
59
+ try {
60
+ const response = await fetch('https://organizedprogrammers-docxtract.hf.space/docs/get_meeting_docs', {
61
+ method: 'POST',
62
+ headers: { 'Content-Type': 'application/json' },
63
+ body: JSON.stringify({ "working_group": wg, "meeting": meeting, "custom_url": null })
64
+ });
65
+
66
+ if (response.ok) {
67
+ const data = await response.json();
68
+ if (data.data && Array.isArray(data.data)) {
69
+ setRawDocs(data.data);
70
+ }
71
+ } else {
72
+ console.error("Failed to fetch docs");
73
+ }
74
+ } catch (error) {
75
+ console.error("Error fetching docs:", error);
76
+ } finally {
77
+ setIsFetchingDocs(false);
78
+ }
79
+ }, []);
80
+
81
+ const handleFilterChange = useCallback((filteredDocs: MeetingDoc[]) => {
82
+ // Convert MeetingDoc to DocumentFile
83
+ const newFiles: DocumentFile[] = filteredDocs.map((doc, index) => ({
84
+ id: doc.TDoc || `doc-${index}`,
85
+ filename: doc.TDoc ? `${doc.TDoc}.zip` : `Document ${index}`,
86
+ size: 'Unknown', // API doesn't provide size
87
+ type: doc.Type,
88
+ uploaded: false,
89
+ status: doc["TDoc Status"],
90
+ agendaItem: doc["Agenda item description"],
91
+ url: doc.URL
92
+ }));
93
+
94
+ setFiles(newFiles);
95
+ setProcessedCount(0);
96
+ setInnovations([]);
97
+ }, []);
98
+
99
+ // Logic: Backend Processing Engine (Phase 2 - SQLite)
100
+ const handleExtractInnovations = async () => {
101
+ if (files.length === 0) return;
102
+ setIsProcessing(true);
103
+ setProcessedCount(0);
104
+ setInnovations([]);
105
+
106
+ // Sequential Processing Logic
107
+ for (let i = 0; i < files.length; i++) {
108
+ const file = files[i];
109
+ setCurrentProcessingFile(file.filename);
110
+
111
+ // Process individually via Backend
112
+ const result = await backendService.processDocument(file, selectedWG, selectedMeeting);
113
+
114
+ if (result) {
115
+ setInnovations(prev => [...prev, result]);
116
+ }
117
+
118
+ setProcessedCount(prev => prev + 1);
119
+ }
120
+
121
+ setIsProcessing(false);
122
+ setCurrentProcessingFile("");
123
+ };
124
+
125
+ const handleClassify = async (id: string, classification: Classification) => {
126
+ // Find the innovation by ID or result_id (since InnovationCard passes result_id)
127
+ const numId = Number(id);
128
+ const targetInv = innovations.find(i => i.id === id || (!isNaN(numId) && i.result_id === numId));
129
+
130
+ if (!targetInv) return;
131
+
132
+ // 1. Update Local State
133
+ setInnovations(prev => prev.map(inv =>
134
+ inv.id === targetInv.id ? { ...inv, classification } : inv
135
+ ));
136
+
137
+ // 2. Persist to Backend if we have a result_id
138
+ if (targetInv.result_id) {
139
+ await backendService.saveClassification(targetInv.result_id, classification);
140
+ }
141
+ };
142
+
143
+ const handleFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
144
+ const file = e.target.files?.[0];
145
+ if (file && file.type === 'text/plain') {
146
+ const reader = new FileReader();
147
+ reader.onload = (event) => {
148
+ const text = event.target?.result as string;
149
+ const newInnovation: Innovation = {
150
+ id: `uploaded-${Date.now()}`,
151
+ file_name: file.name,
152
+ answer: text,
153
+ classification: Classification.UNCLASSIFIED
154
+ };
155
+ setInnovations(prev => [...prev, newInnovation]);
156
+ };
157
+ reader.readAsText(file);
158
+ } else {
159
+ alert("Please upload a .txt file");
160
+ }
161
+ };
162
+
163
+ const handleAnalyze = async () => {
164
+ if (!selectedPatternId) {
165
+ alert("Please select a pattern");
166
+ return;
167
+ }
168
+
169
+ if (innovations.length === 0) {
170
+ alert("No documents to analyze.");
171
+ return;
172
+ }
173
+
174
+ setIsAnalyzing(true);
175
+
176
+ try {
177
+ const updatedInnovations = [...innovations];
178
+
179
+ for (let i = 0; i < updatedInnovations.length; i++) {
180
+ const inv = updatedInnovations[i];
181
+ let result: string | null = null;
182
+ let resultId: number | undefined;
183
+
184
+ // If it's an uploaded file (id starts with uploaded-), pass text content
185
+ if (inv.id.startsWith('uploaded-')) {
186
+ const res = await backendService.analyzeContent(selectedPatternId, undefined, inv.answer);
187
+ if (res) {
188
+ updatedInnovations[i] = {
189
+ ...inv,
190
+ analysis_result: res.content,
191
+ result_id: res.result_id,
192
+ methodology: res.methodology,
193
+ context: res.context,
194
+ problem: res.problem,
195
+ pattern_name: res.pattern_name
196
+ };
197
+ }
198
+ } else {
199
+ // It's a processed doc, pass the ID
200
+ const res = await backendService.analyzeContent(selectedPatternId, inv.id);
201
+ if (res) {
202
+ updatedInnovations[i] = {
203
+ ...inv,
204
+ analysis_result: res.content,
205
+ result_id: res.result_id,
206
+ methodology: res.methodology,
207
+ context: res.context,
208
+ problem: res.problem,
209
+ pattern_name: res.pattern_name
210
+ };
211
+ }
212
+ }
213
+ }
214
+
215
+ setInnovations(updatedInnovations);
216
+ } catch (error) {
217
+ console.error("Error during analysis:", error);
218
+ } finally {
219
+ setIsAnalyzing(false);
220
+ }
221
+ };
222
+
223
+ const pendingInnovations = innovations.filter(i => i.classification !== Classification.DELETE);
224
+ const progressPercent = files.length > 0 ? (processedCount / files.length) * 100 : 0;
225
+
226
+ return (
227
+ <div className="min-h-screen bg-slate-50 font-sans text-slate-900">
228
+
229
+ {/* 1. Header */}
230
+ <header className="bg-slate-900 text-white shadow-md sticky top-0 z-50">
231
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
232
+ <div className="flex justify-between h-16 items-center">
233
+ <div className="flex items-center">
234
+ <div className="bg-blue-500 p-1.5 rounded mr-3">
235
+ <FileText className="h-5 w-5 text-white" />
236
+ </div>
237
+ <div>
238
+ <h1 className="text-lg font-bold tracking-tight">3GPP Innovation Extractor</h1>
239
+ <p className="text-xs text-slate-400">SQLite Backend Powered</p>
240
+ </div>
241
+ </div>
242
+ <nav className="flex space-x-4">
243
+ <button
244
+ onClick={() => setCurrentView('list')}
245
+ className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${currentView === 'list' ? 'bg-slate-800 text-white' : 'text-slate-300 hover:text-white hover:bg-slate-800'}`}
246
+ >
247
+ Extraction
248
+ </button>
249
+ <button
250
+ onClick={() => setCurrentView('dashboard')}
251
+ className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${currentView === 'dashboard' ? 'bg-slate-800 text-white' : 'text-slate-300 hover:text-white hover:bg-slate-800'}`}
252
+ >
253
+ Analytics
254
+ </button>
255
+ </nav>
256
+ </div>
257
+ </div>
258
+ </header>
259
+
260
+ <main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
261
+
262
+ {/* View: Extraction List */}
263
+ <div className={currentView === 'list' ? 'animate-fade-in' : 'hidden'}>
264
+ <FilterBar onFetch={handleFetchDocuments} isFetching={isFetchingDocs} />
265
+
266
+ {rawDocs.length > 0 && (
267
+ <DocFilterBar docs={rawDocs} onFilterChange={handleFilterChange} />
268
+ )}
269
+
270
+ <div className="grid grid-cols-1 lg:grid-cols-12 gap-8">
271
+
272
+ {/* Left Column: Files & Status */}
273
+ <div className="lg:col-span-4 space-y-6">
274
+
275
+ {/* File Stats Card */}
276
+ <div className="bg-white rounded-lg shadow-sm border border-slate-200 p-5">
277
+ <div className="flex items-center justify-between mb-4">
278
+ <h2 className="font-semibold text-slate-800">Documents</h2>
279
+ <span className="text-xs font-mono bg-slate-100 px-2 py-1 rounded text-slate-600">
280
+ {files.length} Files
281
+ </span>
282
+ </div>
283
+
284
+ {files.length === 0 ? (
285
+ <div className="text-center py-8 text-slate-400 text-sm border-2 border-dashed border-slate-100 rounded-lg">
286
+ No documents selected
287
+ </div>
288
+ ) : (
289
+ <div className="mb-4">
290
+ <div className="flex justify-between text-xs text-slate-500 mb-1">
291
+ <span>Processing Progress</span>
292
+ <span>{processedCount} / {files.length}</span>
293
+ </div>
294
+ <div className="h-2 w-full bg-slate-100 rounded-full overflow-hidden">
295
+ <div className="h-full bg-blue-500 transition-all duration-300" style={{ width: `${progressPercent}%` }}></div>
296
+ </div>
297
+ {isProcessing && (
298
+ <p className="text-xs text-blue-500 mt-2 animate-pulse">
299
+ Processing: {currentProcessingFile}
300
+ </p>
301
+ )}
302
+ </div>
303
+ )}
304
+
305
+ <div className="mt-4">
306
+ <button
307
+ onClick={handleExtractInnovations}
308
+ disabled={files.length === 0 || isProcessing}
309
+ className="w-full bg-slate-900 hover:bg-slate-800 text-white font-medium py-3 rounded-lg shadow-md transition-all disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center"
310
+ >
311
+ {isProcessing ? (
312
+ <><CircleDashed className="w-4 h-4 mr-2 animate-spin" /> Processing...</>
313
+ ) : (
314
+ <><Play className="w-4 h-4 mr-2 fill-current" /> Start Extraction</>
315
+ )}
316
+ </button>
317
+ </div>
318
+ </div>
319
+
320
+ {/* Pattern Analysis Card */}
321
+ <div className="bg-white rounded-lg shadow-sm border border-slate-200 p-5">
322
+ <h2 className="font-semibold text-slate-800 mb-4">Pattern Analysis</h2>
323
+
324
+ <div className="space-y-4">
325
+ <div>
326
+ <label className="block text-xs font-medium text-slate-500 mb-1">Select Pattern</label>
327
+ <select
328
+ className="w-full bg-slate-50 border border-slate-200 rounded-md px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
329
+ value={selectedPatternId || ''}
330
+ onChange={(e) => setSelectedPatternId(Number(e.target.value))}
331
+ >
332
+ {patterns.map(p => (
333
+ <option key={p.pattern_id} value={p.pattern_id}>{p.pattern_name}</option>
334
+ ))}
335
+ </select>
336
+ </div>
337
+
338
+ <div>
339
+ <label className="block text-xs font-medium text-slate-500 mb-1">Upload .txt File (Optional)</label>
340
+ <input
341
+ type="file"
342
+ accept=".txt"
343
+ onChange={handleFileUpload}
344
+ className="w-full text-xs text-slate-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-xs file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100"
345
+ />
346
+ {/* Upload status is now handled in the main list */}
347
+ </div>
348
+
349
+ <button
350
+ onClick={handleAnalyze}
351
+ disabled={isAnalyzing || innovations.length === 0}
352
+ className="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 rounded-lg shadow-sm transition-all disabled:opacity-50 flex items-center justify-center text-sm"
353
+ >
354
+ {isAnalyzing ? (
355
+ <><CircleDashed className="w-4 h-4 mr-2 animate-spin" /> Analyzing...</>
356
+ ) : (
357
+ <><Play className="w-4 h-4 mr-2 fill-current" /> Analyse</>
358
+ )}
359
+ </button>
360
+ </div>
361
+ </div>
362
+ </div>
363
+
364
+ {/* Right Column: Results */}
365
+ <div className="lg:col-span-8">
366
+ <div className="flex items-center justify-between mb-4">
367
+ <h2 className="text-xl font-bold text-slate-800">Files content refined</h2>
368
+ {innovations.length > 0 && (
369
+ <span className="text-sm text-slate-500">
370
+ Showing {pendingInnovations.length} potential items
371
+ </span>
372
+ )}
373
+ </div>
374
+
375
+ {innovations.length === 0 ? (
376
+ <div className="bg-white rounded-xl border border-dashed border-slate-300 p-12 text-center">
377
+ <div className="mx-auto bg-slate-50 w-16 h-16 rounded-full flex items-center justify-center mb-4">
378
+ <Settings className="w-8 h-8 text-slate-400" />
379
+ </div>
380
+ <h3 className="text-lg font-medium text-slate-900">Ready to Process</h3>
381
+ <p className="text-slate-500 max-w-sm mx-auto mt-2">
382
+ Load documents and start the extraction engine. The Data will be mocked and stored in your local SQLite database.
383
+ </p>
384
+ </div>
385
+ ) : (
386
+ <div className="space-y-4">
387
+ {pendingInnovations.map(inv => (
388
+ <div key={inv.id}>
389
+ <FileContentCard
390
+ innovation={inv}
391
+ onClassify={handleClassify}
392
+ />
393
+ {inv.analysis_result && (
394
+ <div className="ml-8 mt-2">
395
+ <InnovationCard
396
+ innovation={{
397
+ id: inv.result_id || 0,
398
+ file_name: inv.file_name,
399
+ content: inv.analysis_result || "",
400
+ classification: inv.classification,
401
+ methodology: inv.methodology || "N/A",
402
+ context: inv.context || "N/A",
403
+ problem: inv.problem || "N/A",
404
+ }}
405
+ onClassify={handleClassify}
406
+ />
407
+ </div>
408
+ )}
409
+ </div>
410
+ ))}
411
+ {pendingInnovations.length === 0 && innovations.length > 0 && (
412
+ <div className="text-center py-10 text-slate-500">
413
+ All items have been deleted. Check the Analytics tab for stats.
414
+ </div>
415
+ )}
416
+ </div>
417
+ )}
418
+ </div>
419
+ </div>
420
+ </div>
421
+
422
+
423
+ {/* View: Analytics Dashboard */}
424
+ <div className={currentView === 'dashboard' ? 'animate-fade-in' : 'hidden'}>
425
+ <div className="flex items-center justify-between mb-6">
426
+ <h2 className="text-2xl font-bold text-slate-900">Classification Analytics</h2>
427
+ </div>
428
+
429
+ <StatsDashboard innovations={[]} isVisible={currentView === 'dashboard'} />
430
+
431
+ </div>
432
+
433
+ </main>
434
+ </div>
435
+ );
436
+ };
437
+
438
+ export default App;
Dockerfile ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Stage 1: Build Frontend
2
+ FROM node:20-alpine as build
3
+ WORKDIR /app
4
+ COPY package.json package-lock.json ./
5
+ # Install dependencies
6
+ RUN npm install
7
+ # Copy source code
8
+ COPY . .
9
+ # Build
10
+ RUN npm run build
11
+
12
+ # Stage 2: Run Backend
13
+ FROM python:3.10-slim
14
+
15
+ WORKDIR /app
16
+
17
+ # Install system dependencies
18
+ # RUN apt-get update && apt-get install -y gcc
19
+
20
+ # Install Python dependencies
21
+ COPY backend/requirements.txt .
22
+ RUN pip install --no-cache-dir -r requirements.txt
23
+
24
+ # Copy Backend Code
25
+ # We copy contents of backend/ directly to /app so main.py is at /app/main.py
26
+ COPY backend /app
27
+
28
+ # Copy Built Frontend from Stage 1 to /app/static
29
+ COPY --from=build /app/dist /app/static
30
+
31
+ # Create cache directory for Hugging Face (optional, but good for permissions)
32
+ RUN mkdir -p /app/cache
33
+ ENV HF_HOME=/app/cache
34
+
35
+ # Expose port (HF Spaces uses 7860)
36
+ EXPOSE 7860
37
+
38
+ # Run Application
39
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
README.md CHANGED
@@ -1,11 +1,80 @@
1
- ---
2
- title: 3GPP Innovation Extractor
3
- emoji: 🏢
4
- colorFrom: yellow
5
- colorTo: gray
6
- sdk: docker
7
- pinned: false
8
- short_description: Extract and generate context - problem description from 3GPP
9
- ---
10
-
11
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div align="center">
2
+ <img width="1200" height="475" alt="GHBanner" src="https://github.com/user-attachments/assets/0aa67016-6eaf-458a-adb2-6e31a0763ed6" />
3
+ </div>
4
+
5
+ # Run and deploy your AI Studio app
6
+
7
+ This contains everything you need to run your app locally.
8
+
9
+ View your app in AI Studio: https://ai.studio/apps/drive/1O8Eus7hM_SgPBOyiJCLEArY0Jz76f6bF
10
+
11
+ ## Run Locally
12
+
13
+ **Prerequisites:** Node.js
14
+
15
+
16
+ 1. Install dependencies:
17
+ `npm install`
18
+ 2. Set the `GEMINI_API_KEY` in [.env.local](.env.local) to your Gemini API key
19
+ 3. Run the app:
20
+ `npm run dev`
21
+
22
+
23
+ Workflow Overview
24
+
25
+ ```mermaid
26
+ flowchart TD
27
+ subgraph S1 [Phase 1: Data Ingestion]
28
+ A[User Selects Working Group] -->|SA1-6, RAN1-2| B[Fetch Meetings via POST]
29
+ B --> C[User Selects Meeting]
30
+ C --> D[Filter Docs by Metadata]
31
+ D --> E[Extract Raw Text]
32
+ end
33
+
34
+ subgraph S2 [Phase 2: Refinement & Caching]
35
+ E --> F{Text in Cache?}
36
+ F -- Yes --> G[Retrieve Cached Refinement]
37
+ F -- No --> H[LLM Processing]
38
+ H --> I[Task: Dense Chunking & 'What's New']
39
+ I --> J[Store in Dataset]
40
+ J --> G
41
+ end
42
+
43
+ subgraph S3 [Phase 3: Pattern Analysis]
44
+ G --> K[User Selects Pattern/Prompt]
45
+ K --> L{Result in Cache?}
46
+ L -- Yes --> M[Retrieve Analysis]
47
+ L -- No --> N[Execute Pattern]
48
+ N --> O[Multi-Model Verification]
49
+ O --> P[Store Result]
50
+ end
51
+
52
+ S1 --> S2 --> S3
53
+ ```
54
+
55
+ ### Detailed Process Specification
56
+
57
+ #### Phase 1: Data Ingestion & Extraction
58
+ The user navigates a strict hierarchy to isolate relevant source text.
59
+ 1. **Working Group Selection:** User selects one group from the allowlist: `['SA1', 'SA2', 'SA3', 'SA4', 'SA5', 'SA6', 'RAN1', 'RAN2']`.
60
+ 2. **Meeting Retrieval:** System executes a `POST` request to the endpoint using the selected Working Group to retrieve the meeting list.
61
+ 3. **Document Filtering:** User selects a meeting, then filters the resulting file list using available metadata.
62
+ 4. **Text Extraction:** System extracts raw content from the filtered files into a text list.
63
+
64
+ #### Phase 2: Content Refinement (with Caching)
65
+ Raw text is processed into high-value summaries to reduce noise.
66
+ * **Cache Check:** Before processing, check the dataset for existing `(text_hash, refined_output)` pairs to prevent duplicate processing.
67
+ * **LLM Processing:** If not cached, pass text to the selected LLM (default provided, user-changeable).
68
+ * **Prompt Objective:**
69
+ 1. Create information-dense chunks (minimize near-duplicates).
70
+ 2. Generate a "What's New" paragraph wrapped in `SUGGESTION START` and `SUGGESTION END` tags.
71
+ * **Storage:** Save the input text and the LLM output to the dataset.
72
+
73
+ #### Phase 3: Pattern Analysis & Verification
74
+ Refined text is analyzed using specific user-defined patterns.
75
+ * **Pattern Selection:** User applies a specific prompt/pattern to the refined documents.
76
+ * **Cache Check:** Check the results database for existing `(document_id, pattern_id)` results.
77
+ * **Execution & Verification:**
78
+ * Run the selected pattern against the documents.
79
+ * **Verifier Mode:** Optionally execute the same input across multiple models simultaneously to compare results and ensure accuracy.
80
+ * **Storage:** Save the final analysis in the database to prevent future re-computation.
backend/.env ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ GEMINI_API_KEY=AIzaSyC9XHvWz4gxQAJoUyuiK07EaZct53dHtgE
2
+ GROQ_API_KEY=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
backend/__init__.py ADDED
File without changes
backend/__pycache__/data_service.cpython-310.pyc ADDED
Binary file (8.04 kB). View file
 
backend/__pycache__/main.cpython-310.pyc ADDED
Binary file (8.8 kB). View file
 
backend/__pycache__/patterns.cpython-310.pyc ADDED
Binary file (2.41 kB). View file
 
backend/data_service.py ADDED
@@ -0,0 +1,326 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import os
3
+ import pandas as pd
4
+ from datasets import load_dataset, Dataset, DatasetDict
5
+ from huggingface_hub import login
6
+ import logging
7
+ from typing import List, Optional, Dict, Any
8
+
9
+ from dotenv import load_dotenv
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ # Load envs
14
+ load_dotenv()
15
+ load_dotenv("../.env.local")
16
+
17
+ class DataService:
18
+ def __init__(self):
19
+ self.hf_token = os.getenv("HF_TOKEN")
20
+ self.dataset_name = os.getenv("HF_DATASET_NAME")
21
+
22
+ if not self.hf_token or not self.dataset_name:
23
+ logger.error("HF_TOKEN or HF_DATASET_NAME not set via environment variables.")
24
+ # We might want to raise an error here or handle it gracefully if running locally without HF
25
+ # For now, we'll log error.
26
+
27
+ if self.hf_token:
28
+ login(token=self.hf_token)
29
+
30
+ self.configs = ["files", "refined", "patterns", "results"]
31
+ self.data: Dict[str, pd.DataFrame] = {}
32
+
33
+ self._load_data()
34
+
35
+ def _load_data(self):
36
+ """Loads data from HF Hub for each config. Initializes empty if not found."""
37
+ for config in self.configs:
38
+ try:
39
+ # trust_remote_code=True is sometimes needed, but for simple datasets usually not.
40
+ # using split="train" by default as load_dataset returns a DatasetDict if split not specified
41
+ ds = load_dataset(self.dataset_name, config, split="train")
42
+ self.data[config] = ds.to_pandas()
43
+ logger.info(f"Loaded config '{config}' with {len(self.data[config])} rows.")
44
+ except Exception as e:
45
+ logger.warning(f"Could not load config '{config}' from HF: {e}. Initializing empty.")
46
+ self.data[config] = pd.DataFrame()
47
+
48
+ def _save(self, config_name: str):
49
+ """Pushes the specific config DataFrame to HF Hub."""
50
+ if not self.hf_token or not self.dataset_name:
51
+ logger.warning("Skipping save to HF: Credentials missing.")
52
+ return
53
+
54
+ try:
55
+ df = self.data[config_name]
56
+ # Convert DataFrame to Dataset
57
+ ds = Dataset.from_pandas(df)
58
+ # Push to hub
59
+ # We need to preserve the columns.
60
+ ds.push_to_hub(self.dataset_name, config_name=config_name, token=self.hf_token)
61
+ logger.info(f"Saved config '{config_name}' to HF Hub.")
62
+ except Exception as e:
63
+ logger.error(f"Failed to save config '{config_name}': {e}")
64
+
65
+ # --- Schema Helpers ---
66
+ # These ensure we have the right columns even if empty
67
+
68
+ def _ensure_columns(self, config, columns):
69
+ if self.data[config].empty:
70
+ self.data[config] = pd.DataFrame(columns=columns)
71
+ else:
72
+ # Add missing columns if any
73
+ for col in columns:
74
+ if col not in self.data[config].columns:
75
+ self.data[config][col] = None
76
+
77
+ # --- File Operations ---
78
+
79
+ def get_all_files(self) -> List[Dict[str, Any]]:
80
+ if self.data["files"].empty:
81
+ return []
82
+ return self.data["files"].to_dict(orient="records")
83
+
84
+ def get_file_content(self, file_id: str) -> Optional[str]:
85
+ df = self.data["files"]
86
+ if df.empty: return None
87
+ row = df[df["file_id"] == file_id]
88
+ if not row.empty:
89
+ return row.iloc[0]["content"]
90
+ return None
91
+
92
+ def add_file(self, file_data: Dict[str, Any]):
93
+ self._ensure_columns("files", ["file_id", "working_group", "meeting", "type", "status", "agenda_item", "content", "filename", "timestamp"])
94
+ df = self.data["files"]
95
+
96
+ # Check if exists
97
+ if not df.empty and file_id in df["file_id"].values:
98
+ # Update? Or Skip? The original code did INSERT, so it might fail on duplicate PK usually?
99
+ # SQLite: INSERT INTO file ... (if PK integrity error, it fails).
100
+ # We will overwrite if exists for simplicity or skip.
101
+ # Let's overwrite.
102
+ file_id = file_data["file_id"]
103
+ df = df[df["file_id"] != file_id]
104
+
105
+ # Add new row
106
+ new_row = pd.DataFrame([file_data])
107
+ self.data["files"] = pd.concat([df, new_row], ignore_index=True)
108
+ self._save("files")
109
+
110
+ # --- Refined Operations ---
111
+
112
+ def get_refined_output(self, file_id: str) -> Optional[str]:
113
+ df = self.data["refined"]
114
+ if df.empty: return None
115
+ row = df[df["file_id"] == file_id]
116
+ if not row.empty:
117
+ return row.iloc[0]["refined_output"]
118
+ return None
119
+
120
+ def add_refined(self, file_id: str, refined_output: str) -> int:
121
+ self._ensure_columns("refined", ["refined_id", "refined_output", "file_id"])
122
+ df = self.data["refined"]
123
+
124
+ # Generate ID
125
+ next_id = 1
126
+ if not df.empty:
127
+ # check max. If refined_id is not numeric (e.g. None), handle it.
128
+ # Assuming it is numeric as per SQLite schema
129
+ max_id = pd.to_numeric(df["refined_id"]).max()
130
+ if not pd.isna(max_id):
131
+ next_id = int(max_id) + 1
132
+
133
+ new_row = pd.DataFrame([{
134
+ "refined_id": next_id,
135
+ "refined_output": refined_output,
136
+ "file_id": file_id
137
+ }])
138
+
139
+ self.data["refined"] = pd.concat([df, new_row], ignore_index=True)
140
+ self._save("refined")
141
+ return next_id
142
+
143
+ def get_refined_by_file_id(self, file_id: str):
144
+ df = self.data["refined"]
145
+ if df.empty: return None
146
+ row = df[df["file_id"] == file_id]
147
+ if not row.empty:
148
+ return row.iloc[0].to_dict()
149
+ return None
150
+
151
+ # --- Pattern Operations ---
152
+
153
+ def get_patterns(self) -> List[Dict[str, Any]]:
154
+ if self.data["patterns"].empty:
155
+ return []
156
+ return self.data["patterns"].to_dict(orient="records")
157
+
158
+ def get_pattern(self, pattern_id: int):
159
+ df = self.data["patterns"]
160
+ if df.empty: return None
161
+ row = df[df["pattern_id"] == pattern_id]
162
+ if not row.empty:
163
+ return row.iloc[0].to_dict()
164
+ return None
165
+
166
+ def add_pattern(self, pattern_name: str, prompt: str) -> int:
167
+ self._ensure_columns("patterns", ["pattern_id", "pattern_name", "prompt"])
168
+ df = self.data["patterns"]
169
+
170
+ next_id = 1
171
+ if not df.empty:
172
+ max_id = pd.to_numeric(df["pattern_id"]).max()
173
+ if not pd.isna(max_id):
174
+ next_id = int(max_id) + 1
175
+
176
+ new_row = pd.DataFrame([{
177
+ "pattern_id": next_id,
178
+ "pattern_name": pattern_name,
179
+ "prompt": prompt
180
+ }])
181
+ self.data["patterns"] = pd.concat([df, new_row], ignore_index=True)
182
+ self._save("patterns")
183
+ return next_id
184
+
185
+ def update_pattern(self, pattern_id: int, pattern_name: str, prompt: str):
186
+ df = self.data["patterns"]
187
+ if df.empty: return False
188
+
189
+ # Check if exists
190
+ if pattern_id not in df["pattern_id"].values:
191
+ return False
192
+
193
+ # Update
194
+ self.data["patterns"].loc[df["pattern_id"] == pattern_id, ["pattern_name", "prompt"]] = [pattern_name, prompt]
195
+ self._save("patterns")
196
+ return True
197
+
198
+ # --- Result Operations ---
199
+
200
+ def get_existing_result(self, file_id: str):
201
+ """
202
+ Equivalent to:
203
+ SELECT ... FROM result r JOIN refined ref ... WHERE refined.file_id = ?
204
+ """
205
+ # First get refined_id for file_id
206
+ ref_row = self.get_refined_by_file_id(file_id)
207
+ file_df = self.data["files"]
208
+ file_name = "Unknown File"
209
+ if not file_df.empty:
210
+ f_row = file_df[file_df["file_id"] == file_id]
211
+ if not f_row.empty:
212
+ file_name = f_row.iloc[0]["filename"]
213
+
214
+ if not ref_row:
215
+ return None, None, file_name
216
+
217
+ refined_id = ref_row["refined_id"]
218
+
219
+ # Search in results
220
+ res_df = self.data["results"]
221
+ if res_df.empty:
222
+ return None, refined_id, file_name
223
+
224
+ # Filter where refined_id matches
225
+ # Note: result has refined_id
226
+ match = res_df[res_df["refined_id"] == refined_id]
227
+
228
+ if match.empty:
229
+ return None, refined_id, file_name
230
+
231
+ # Use the LAST result if multiple? Original SQL used simple join, usually implies 1-to-1 or fetchone
232
+ # We'll take the first one or last one.
233
+ result_row = match.iloc[-1].to_dict() # latest
234
+
235
+ # Need pattern name
236
+ pat_df = self.data["patterns"]
237
+ pattern_name = "Unknown"
238
+ if not pat_df.empty and "pattern_id" in result_row:
239
+ pat_match = pat_df[pat_df["pattern_id"] == result_row["pattern_id"]]
240
+ if not pat_match.empty:
241
+ pattern_name = pat_match.iloc[0]["pattern_name"]
242
+
243
+ result_row["pattern_name"] = pattern_name
244
+ # normalize keys to match what main.py expects (content vs result_content)
245
+ # Main.py expects 'content' key for result_content
246
+ result_row["content"] = result_row.get("result_content")
247
+
248
+ return result_row, refined_id, file_name
249
+
250
+ def add_result(self, pattern_id: int, refined_id: int, result_content: str, methodology: str, context: str, problem: str, classification: str = "UNCLASSIFIED") -> int:
251
+ self._ensure_columns("results", ["result_id", "pattern_id", "refined_id", "result_content", "methodology", "context", "problem", "classification"])
252
+ df = self.data["results"]
253
+
254
+ next_id = 1
255
+ if not df.empty:
256
+ max_id = pd.to_numeric(df["result_id"]).max()
257
+ if not pd.isna(max_id):
258
+ next_id = int(max_id) + 1
259
+
260
+ new_row = pd.DataFrame([{
261
+ "result_id": next_id,
262
+ "pattern_id": pattern_id,
263
+ "refined_id": refined_id,
264
+ "result_content": result_content,
265
+ "methodology": methodology,
266
+ "context": context,
267
+ "problem": problem,
268
+ "classification": classification
269
+ }])
270
+
271
+ self.data["results"] = pd.concat([df, new_row], ignore_index=True)
272
+ self._save("results")
273
+ return next_id
274
+
275
+ def update_classification(self, result_id: int, classification: str):
276
+ df = self.data["results"]
277
+ if df.empty: raise Exception("No results found")
278
+
279
+ if result_id not in df["result_id"].values:
280
+ return False
281
+
282
+ self.data["results"].loc[df["result_id"] == result_id, "classification"] = classification
283
+ self._save("results")
284
+ return True
285
+
286
+ def get_all_results_joined(self):
287
+ """
288
+ Joins results, refined, file, pattern
289
+ """
290
+ if self.data["results"].empty:
291
+ return []
292
+
293
+ res_df = self.data["results"].copy()
294
+
295
+ # Join Patterns
296
+ pat_df = self.data["patterns"]
297
+ if not pat_df.empty:
298
+ res_df = res_df.merge(pat_df[["pattern_id", "pattern_name"]], on="pattern_id", how="left")
299
+
300
+ # Join Refined
301
+ ref_df = self.data["refined"]
302
+ if not ref_df.empty:
303
+ res_df = res_df.merge(ref_df[["refined_id", "file_id"]], on="refined_id", how="left")
304
+
305
+ # Join File
306
+ def_file = self.data["files"]
307
+ if not def_file.empty:
308
+ res_df = res_df.merge(def_file[["file_id", "filename"]], on="file_id", how="left")
309
+
310
+ # Select/Rename for output
311
+ # Mappings based on API: id, file_name, content, classification, pattern_name, etc.
312
+ out = []
313
+ for _, row in res_df.iterrows():
314
+ out.append({
315
+ "id": row.get("result_id"),
316
+ "file_name": row.get("filename"),
317
+ "content": row.get("result_content"),
318
+ "classification": row.get("classification"),
319
+ "pattern_name": row.get("pattern_name"),
320
+ "methodology": row.get("methodology"),
321
+ "context": row.get("context"),
322
+ "problem": row.get("problem")
323
+ })
324
+ # sort desc by id
325
+ out.sort(key=lambda x: x["id"] or 0, reverse=True)
326
+ return out
backend/main.py ADDED
@@ -0,0 +1,378 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ from datetime import datetime
3
+ from fastapi import FastAPI, HTTPException, BackgroundTasks
4
+ from fastapi.staticfiles import StaticFiles
5
+ from fastapi.responses import FileResponse
6
+ from pydantic import BaseModel
7
+ from fastapi.middleware.cors import CORSMiddleware
8
+ from google import genai
9
+ from dotenv import load_dotenv
10
+ import os
11
+ import json
12
+ import logging
13
+ import re
14
+ import mistune
15
+ import requests
16
+ from data_service import DataService
17
+
18
+ # Load envs
19
+ load_dotenv()
20
+ load_dotenv("../.env.local")
21
+
22
+ GROQ_API_KEY = os.getenv("GROQ_API_KEY")
23
+ GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
24
+
25
+ # Configure Logging
26
+ logging.basicConfig(level=logging.INFO)
27
+ logger = logging.getLogger(__name__)
28
+
29
+ app = FastAPI(title="3GPP Innovation Backend")
30
+
31
+ # Initialize DataService
32
+ data_service = DataService()
33
+
34
+ # CORS Setup
35
+ origins = [
36
+ "http://localhost:5173",
37
+ "http://localhost:3000",
38
+ "*"
39
+ ]
40
+
41
+ app.add_middleware(
42
+ CORSMiddleware,
43
+ allow_origins=origins,
44
+ allow_credentials=True,
45
+ allow_methods=["*"],
46
+ allow_headers=["*"],
47
+ )
48
+
49
+
50
+ def ask_gemini(prompt, content):
51
+ MAX_LEN = 10000
52
+
53
+ if len(prompt) + len(content) <= MAX_LEN:
54
+ client = genai.Client(api_key=GEMINI_API_KEY)
55
+ response = client.models.generate_content(
56
+ model="gemma-3-27b-it",
57
+ contents=prompt + "\n\n" + content
58
+ )
59
+ return response.text
60
+
61
+ chunk = content[:MAX_LEN - len(prompt)]
62
+ rest = content[MAX_LEN - len(prompt):]
63
+
64
+ first_answer = ask_gemini(prompt, chunk)
65
+ #remaining_answer = ask_gemini(prompt, rest)
66
+
67
+ return first_answer #+ "\n\n" + remaining_answer
68
+
69
+ PROCESS_PROMPT = """
70
+ Task :
71
+ Using the text provided,
72
+ create chunk that are dense in relevant information and minimize near-duplicate or
73
+ loosely related passages, provide a paragraph on whats new to this document using
74
+ the SUGGESTION START and END.
75
+ """
76
+
77
+ def format_answer(answer):
78
+ return f"We obtained the following methodology:"+answer["methodology"]+"\n\nThe context is :"+answer["context"]+"\n\nThe problem description is :"+answer["problem"]
79
+
80
+ def extract_json(text: str) -> dict:
81
+ match = re.search(r'\{.*\}', text, re.DOTALL)
82
+ if not match:
83
+ raise ValueError("Aucun JSON trouvé")
84
+ return json.loads(match.group())
85
+
86
+ # --- Pydantic Models ---
87
+
88
+ class ProcessRequest(BaseModel):
89
+ file_id: str
90
+ filename: str
91
+ working_group: str
92
+ meeting: str
93
+ type: str # doc.Type
94
+ status: str # doc["TDoc Status"]
95
+ agenda_item: str # doc["Agenda item description"]
96
+ url: str
97
+
98
+ class InnovationResponse(BaseModel):
99
+ id: str
100
+ file_name: str
101
+ answer: str
102
+ classification: str
103
+
104
+ class PatternResponse(BaseModel):
105
+ pattern_id: int
106
+ pattern_name: str
107
+ prompt: str
108
+
109
+ class AnalyzeRequest(BaseModel):
110
+ file_id: str = None
111
+ text: str = None
112
+ pattern_id: int
113
+
114
+ class AnalyzeResponse(BaseModel):
115
+ id: int
116
+ file_name: str
117
+ content: str
118
+ methodology: str
119
+ context: str
120
+ problem: str
121
+ pattern_name: str
122
+
123
+ class ClassificationRequest(BaseModel):
124
+ result_id: int
125
+ classification: str
126
+
127
+ class ResultResponse(BaseModel):
128
+ id: int
129
+ file_name: str
130
+ content: str
131
+ classification: str
132
+ pattern_name: str
133
+ methodology: str
134
+ context: str
135
+ problem: str
136
+
137
+ # --- Helper Functions ---
138
+
139
+ def fetch_text_content(req: AnalyzeRequest):
140
+ """
141
+ fetches text content from request or database.
142
+ """
143
+ if req.text:
144
+ return req.text
145
+ elif req.file_id:
146
+ content = data_service.get_file_content(req.file_id)
147
+ if content:
148
+ return content
149
+ else:
150
+ refined = data_service.get_refined_output(req.file_id)
151
+ if refined:
152
+ return refined
153
+ return None
154
+
155
+ # --- API Endpoints ---
156
+
157
+ @app.get("/get_all")
158
+ def get_all():
159
+ return data_service.get_all_files()
160
+
161
+ @app.get("/patterns", response_model=list[PatternResponse])
162
+ def get_patterns():
163
+ return data_service.get_patterns()
164
+
165
+ class PatternRequest(BaseModel):
166
+ pattern_name: str
167
+ prompt: str
168
+
169
+ @app.post("/patterns", response_model=PatternResponse)
170
+ def create_pattern(req: PatternRequest):
171
+ try:
172
+ pattern_id = data_service.add_pattern(req.pattern_name, req.prompt)
173
+ return {
174
+ "pattern_id": pattern_id,
175
+ "pattern_name": req.pattern_name,
176
+ "prompt": req.prompt
177
+ }
178
+ except Exception as e:
179
+ logger.error(f"Error creating pattern: {e}")
180
+ raise HTTPException(status_code=500, detail=str(e))
181
+
182
+ @app.put("/patterns/{pattern_id}", response_model=PatternResponse)
183
+ def update_pattern(pattern_id: int, req: PatternRequest):
184
+ try:
185
+ updated = data_service.update_pattern(pattern_id, req.pattern_name, req.prompt)
186
+ if not updated:
187
+ raise HTTPException(status_code=404, detail="Pattern not found")
188
+
189
+ return {
190
+ "pattern_id": pattern_id,
191
+ "pattern_name": req.pattern_name,
192
+ "prompt": req.prompt
193
+ }
194
+ except HTTPException as he:
195
+ raise he
196
+ except Exception as e:
197
+ logger.error(f"Error updating pattern: {e}")
198
+ raise HTTPException(status_code=500, detail=str(e))
199
+
200
+ @app.post("/analyze", response_model=AnalyzeResponse)
201
+ async def analyze_content(req: AnalyzeRequest):
202
+ print("Start of analyse")
203
+
204
+ try:
205
+ # 1. Check for existing result (caching strategy)
206
+ existing_result, refined_id, file_name = data_service.get_existing_result(req.file_id)
207
+
208
+ if existing_result:
209
+ # Cache Hit
210
+ return {
211
+ "id": existing_result['result_id'],
212
+ "file_name": file_name,
213
+ "content": existing_result['content'],
214
+ "methodology": existing_result['methodology'],
215
+ "context": existing_result['context'],
216
+ "problem": existing_result['problem'],
217
+ "pattern_name": existing_result['pattern_name']
218
+ }
219
+
220
+ # 2. Cache Miss - Perform Analysis
221
+ print('Performing new analysis')
222
+ text_content = fetch_text_content(req)
223
+
224
+ if not text_content:
225
+ raise HTTPException(status_code=400, detail="No content found to analyze")
226
+
227
+ pattern = data_service.get_pattern(req.pattern_id)
228
+ if not pattern:
229
+ raise HTTPException(status_code=404, detail="Pattern not found")
230
+
231
+ pattern_name = pattern['pattern_name']
232
+ pattern_prompt = pattern['prompt']
233
+
234
+ # Call LLM
235
+ response = ask_gemini(f"Pattern: {pattern_name}\nPrompt: {pattern_prompt}\n\nContext:\n", text_content)
236
+ json_response = extract_json(response)
237
+ answer = format_answer(json_response)
238
+
239
+ methodology = json_response["methodology"]
240
+ context = json_response["context"]
241
+ problem = json_response["problem"]
242
+
243
+ # Save Result
244
+ # We need refined_id. If get_existing_result returned it (even if no result matched), use it.
245
+ # But get_existing_result returns it.
246
+ # If refined_id is None, it means the file wasn't refined?
247
+ # Ideally fetch_text_content doesn't give refined_id.
248
+ # Let's get refined_id again if missing.
249
+ if not refined_id and req.file_id:
250
+ ref_row = data_service.get_refined_by_file_id(req.file_id)
251
+ if ref_row:
252
+ refined_id = ref_row["refined_id"]
253
+
254
+ result_id = data_service.add_result(req.pattern_id, refined_id, answer, methodology, context, problem)
255
+
256
+ print("End of analyse")
257
+ return {
258
+ "id": result_id,
259
+ "file_name": file_name,
260
+ "content": answer,
261
+ "methodology": methodology,
262
+ "context": context,
263
+ "problem": problem,
264
+ "pattern_name": pattern_name
265
+ }
266
+
267
+ except Exception as e:
268
+ logger.error(f"Error during analysis: {e}")
269
+ raise HTTPException(status_code=500, detail=str(e))
270
+
271
+
272
+ @app.post("/classify")
273
+ def classify_result(req: ClassificationRequest):
274
+ try:
275
+ updated = data_service.update_classification(req.result_id, req.classification)
276
+ if not updated:
277
+ raise HTTPException(status_code=404, detail="Result not found")
278
+ return {"id": req.result_id, "status": "updated"}
279
+ except Exception as e:
280
+ logger.error(f"Error updating classification: {e}")
281
+ raise HTTPException(status_code=500, detail=str(e))
282
+
283
+ @app.get("/results", response_model=list[ResultResponse])
284
+ def get_results():
285
+ try:
286
+ return data_service.get_all_results_joined()
287
+ except Exception as e:
288
+ logger.error(f"Error fetching results: {e}")
289
+ return []
290
+
291
+
292
+ @app.post("/process", response_model=InnovationResponse)
293
+ async def process_document(req: ProcessRequest):
294
+ try:
295
+ existing_content = data_service.get_file_content(req.file_id)
296
+
297
+ text_content = ""
298
+ content = ""
299
+
300
+ if existing_content:
301
+ logger.info(f"File {req.file_id} found in DB.")
302
+ text_content = existing_content
303
+ else:
304
+ try:
305
+ print(req.url)
306
+ hf_response = requests.post(
307
+ 'https://organizedprogrammers-docxtract.hf.space/docs/extract_text_from_url',
308
+ json={"url": req.url},
309
+ timeout=30
310
+ )
311
+
312
+ if hf_response.status_code == 200:
313
+ data = hf_response.json()
314
+ text_content = data.get('text') or data.get('content') or ""
315
+ else:
316
+ logger.error(f"Failed to fetch content from HF: {hf_response.text}")
317
+ text_content = "Extraction failed."
318
+ except Exception as e:
319
+ logger.error(f"Error fetching content: {e}")
320
+ text_content = "Extraction error."
321
+
322
+ # Add file to DataService
323
+ data_service.add_file({
324
+ "file_id": req.file_id,
325
+ "working_group": req.working_group,
326
+ "meeting": req.meeting,
327
+ "type": req.type,
328
+ "status": req.status,
329
+ "agenda_item": req.agenda_item,
330
+ "content": text_content,
331
+ "filename": req.filename,
332
+ "timestamp": datetime.now().isoformat()
333
+ })
334
+
335
+ refined_output = data_service.get_refined_output(req.file_id)
336
+
337
+ md = mistune.create_markdown()
338
+ if refined_output:
339
+ content = md(refined_output)
340
+ else:
341
+ print(text_content)
342
+ answer = ask_gemini(PROCESS_PROMPT, text_content)
343
+
344
+ content = md(answer)
345
+
346
+ data_service.add_refined(req.file_id, answer)
347
+
348
+ return {
349
+ "id": req.file_id,
350
+ "file_name": req.filename,
351
+ "answer": content,
352
+ "classification": "UNCLASSIFIED",
353
+ }
354
+
355
+ except Exception as e:
356
+ logger.error(f"Error processing: {e}")
357
+ raise HTTPException(status_code=500, detail=str(e))
358
+
359
+ import uvicorn
360
+ uvicorn.run(app, host="0.0.0.0", port=8000)
361
+
362
+ # Serve Static Files for Deployment (must be after API routes)
363
+ static_dir = "static"
364
+ if os.path.exists(static_dir):
365
+ # Mount assets folder
366
+ if os.path.exists(os.path.join(static_dir, "assets")):
367
+ app.mount("/assets", StaticFiles(directory=os.path.join(static_dir, "assets")), name="assets")
368
+
369
+ # Catch-all for SPA and other static files at root
370
+ @app.get("/{full_path:path}")
371
+ async def serve_frontend(full_path: str):
372
+ # Check if it's a specific file that exists
373
+ file_path = os.path.join(static_dir, full_path)
374
+ if os.path.isfile(file_path):
375
+ return FileResponse(file_path)
376
+
377
+ # Default to index.html for SPA routing
378
+ return FileResponse(os.path.join(static_dir, "index.html"))
backend/migrate_db.py ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import sqlite3
3
+ import pandas as pd
4
+ import os
5
+ from dotenv import load_dotenv
6
+ from huggingface_hub import login
7
+ from datasets import Dataset
8
+
9
+ # Load env vars
10
+ load_dotenv()
11
+ load_dotenv("../.env.local") # Try loading from root .env.local as well
12
+ HF_TOKEN = os.getenv("HF_TOKEN")
13
+ HF_DATASET_NAME = os.getenv("HF_DATASET_NAME")
14
+
15
+ if not HF_TOKEN or not HF_DATASET_NAME:
16
+ print("Error: HF_TOKEN or HF_DATASET_NAME not found in environment.")
17
+ exit(1)
18
+
19
+ login(token=HF_TOKEN)
20
+
21
+ DB_FILE = "innovations.db"
22
+
23
+ def migrate():
24
+ conn = sqlite3.connect(DB_FILE)
25
+
26
+ # 1. Migrate Files
27
+ print("Migrating 'file' table...")
28
+ try:
29
+ df_files = pd.read_sql_query("SELECT * FROM file", conn)
30
+ if not df_files.empty:
31
+ ds = Dataset.from_pandas(df_files)
32
+ ds.push_to_hub(HF_DATASET_NAME, config_name="files", token=HF_TOKEN)
33
+ print(f"Pushed {len(df_files)} rows to 'files' config.")
34
+ else:
35
+ print("Table 'file' is empty.")
36
+ except Exception as e:
37
+ print(f"Error migrating 'file': {e}")
38
+
39
+ # 2. Migrate Refined
40
+ print("Migrating 'refined' table...")
41
+ try:
42
+ df_refined = pd.read_sql_query("SELECT * FROM refined", conn)
43
+ if not df_refined.empty:
44
+ ds = Dataset.from_pandas(df_refined)
45
+ ds.push_to_hub(HF_DATASET_NAME, config_name="refined", token=HF_TOKEN)
46
+ print(f"Pushed {len(df_refined)} rows to 'refined' config.")
47
+ else:
48
+ print("Table 'refined' is empty.")
49
+ except Exception as e:
50
+ print(f"Error migrating 'refined': {e}")
51
+
52
+ # 3. Migrate Patterns
53
+ print("Migrating 'pattern' table...")
54
+ try:
55
+ df_patterns = pd.read_sql_query("SELECT * FROM pattern", conn)
56
+ if not df_patterns.empty:
57
+ ds = Dataset.from_pandas(df_patterns)
58
+ ds.push_to_hub(HF_DATASET_NAME, config_name="patterns", token=HF_TOKEN)
59
+ print(f"Pushed {len(df_patterns)} rows to 'patterns' config.")
60
+ else:
61
+ print("Table 'pattern' is empty.")
62
+ except Exception as e:
63
+ print(f"Error migrating 'pattern': {e}")
64
+
65
+ # 4. Migrate Results
66
+ print("Migrating 'result' table...")
67
+ try:
68
+ df_results = pd.read_sql_query("SELECT * FROM result", conn)
69
+ if not df_results.empty:
70
+ ds = Dataset.from_pandas(df_results)
71
+ ds.push_to_hub(HF_DATASET_NAME, config_name="results", token=HF_TOKEN)
72
+ print(f"Pushed {len(df_results)} rows to 'results' config.")
73
+ else:
74
+ print("Table 'result' is empty.")
75
+ except Exception as e:
76
+ print(f"Error migrating 'result': {e}")
77
+
78
+ conn.close()
79
+ print("Migration complete!")
80
+
81
+ if __name__ == "__main__":
82
+ migrate()
backend/patterns.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ patterns = [
2
+ {
3
+ "pattern_name": "TRIZ method",
4
+ "prompt": """
5
+ # On the provided context follow this step-by-step Process
6
+
7
+ ## Step-by-Step Process
8
+ 1. Identify the contradiction - "IF I improve X, THEN Y worsens"
9
+ 2. Map to TRIZ parameters - Find which of the 39 parameters best match X and Y
10
+ 3. Locate intersection - Find the cell where improving parameter (row) meets worsening parameter (column)
11
+ 4. Read suggested principles - The cell contains 3-4 principle numbers ranked by frequency of use
12
+ 5. Apply principles - Interpret each suggested principle in your specific context
13
+ 6. Generate a context and problem description - Find in this context the most important and innovative problem, write its context and description
14
+
15
+ ### The Contradiction Matrix is a 39×39 table where:
16
+ • Rows represent the parameter you want to IMPROVE
17
+ • Columns represent the parameter that WORSENS
18
+ • Intersections contain suggested Inventive Principles (by number)
19
+ Complete Parameter List
20
+ No. Parameter No. Parameter
21
+ 1 Weight of moving object 21 Power
22
+ 2 Weight of stationary object 22 Waste of energy
23
+ 3 Length of moving object 23 Waste of substance
24
+ 4 Length of stationary object 24 Loss of information
25
+ 5 Area of moving object 25 Waste of time
26
+ 6 Area of stationary object 26 Amount of substance
27
+ 7 Volume of moving object 27 Reliability
28
+ 8 Volume of stationary object 28 Accuracy of measurement
29
+ 9 Speed 29 Accuracy of manufacturing
30
+ 10 Force 30 Harmful factors acting on object
31
+ 11 Tension, pressure 31 Harmful side effects
32
+ 12 Shape 32 Manufacturability
33
+ 13 Stability of object 33 Convenience of use
34
+ 14 Strength 34 Repairability
35
+ 15 Durability of moving object 35 Adaptability
36
+ 16 Durability of stationary object 36 Complexity of device
37
+ 17 Temperature 37 Complexity of control
38
+ 18 Brightness 38 Level of automation
39
+ 19 Energy spent by moving object 39 Productivity
40
+ 20 Energy spent by stationary object
41
+
42
+ ### Return the answer as a valid JSON object
43
+ Follow this schema:
44
+ {'methodology': string,
45
+ 'context': string,
46
+ 'problem': string
47
+ }.
48
+
49
+ In methodology provide the all of the content of step 1, 2, 3, 4 and 5.
50
+ In Context provide the generated context at the step 6.
51
+ In Problem provide the generated problem description at the step 6.
52
+ """}
53
+ ]
backend/requirements.txt ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ pydantic
4
+ python-multipart
5
+ requests
6
+ groq
7
+ python-dotenv
8
+ huggingface_hub
9
+ datasets
10
+ pandas
11
+ google-genai
12
+ mistune
components/DocFilterBar.tsx ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState, useEffect } from 'react';
2
+ import { MeetingDoc } from '../types';
3
+ import { Filter, X } from 'lucide-react';
4
+
5
+ interface DocFilterBarProps {
6
+ docs: MeetingDoc[];
7
+ onFilterChange: (filteredDocs: MeetingDoc[]) => void;
8
+ }
9
+
10
+ const DocFilterBar: React.FC<DocFilterBarProps> = ({ docs, onFilterChange }) => {
11
+ // Extract unique values
12
+ const allTypes = Array.from(new Set<string>(docs.map(d => d.Type))).sort();
13
+ const allStatuses = Array.from(new Set<string>(docs.map(d => d['TDoc Status']))).sort();
14
+ const allAgendas = Array.from(new Set<string>(docs.map(d => d['Agenda item description']))).sort();
15
+
16
+ // Default selections
17
+ const defaultTypes = ["LS out", "LS in", "pCR", "CR"];
18
+ const defaultStatuses = ["noted", "revised", "approved", "agreed"];
19
+
20
+ // State
21
+ const [selectedTypes, setSelectedTypes] = useState<string[]>([]);
22
+ const [selectedStatuses, setSelectedStatuses] = useState<string[]>([]);
23
+ const [selectedAgendas, setSelectedAgendas] = useState<string[]>([]);
24
+
25
+ // Initialize defaults when docs change
26
+ useEffect(() => {
27
+ if (docs.length > 0) {
28
+ const initialTypes = allTypes.filter(t => defaultTypes.includes(t));
29
+ // If no default types match, maybe select all or none? Let's stick to defaults.
30
+ // If the default list is empty (none found), user can select manually.
31
+ setSelectedTypes(initialTypes.length > 0 ? initialTypes : []);
32
+
33
+ const initialStatuses = allStatuses.filter(s => defaultStatuses.includes(s));
34
+ setSelectedStatuses(initialStatuses.length > 0 ? initialStatuses : []);
35
+
36
+ // Select all agendas by default
37
+ setSelectedAgendas(allAgendas);
38
+ }
39
+ }, [docs]); // Re-run when docs source changes
40
+
41
+ // Filter logic
42
+ useEffect(() => {
43
+ const filtered = docs.filter(doc => {
44
+ const typeMatch = selectedTypes.length === 0 || selectedTypes.includes(doc.Type);
45
+ const statusMatch = selectedStatuses.length === 0 || selectedStatuses.includes(doc['TDoc Status']);
46
+ const agendaMatch = selectedAgendas.length === 0 || selectedAgendas.includes(doc['Agenda item description']);
47
+ return typeMatch && statusMatch && agendaMatch;
48
+ });
49
+ onFilterChange(filtered);
50
+ }, [selectedTypes, selectedStatuses, selectedAgendas, docs]);
51
+
52
+
53
+ const toggleSelection = (item: string, current: string[], setter: (val: string[]) => void) => {
54
+ if (current.includes(item)) {
55
+ setter(current.filter(i => i !== item));
56
+ } else {
57
+ setter([...current, item]);
58
+ }
59
+ };
60
+
61
+ const toggleAll = (all: string[], current: string[], setter: (val: string[]) => void) => {
62
+ if (current.length === all.length) {
63
+ setter([]);
64
+ } else {
65
+ setter(all);
66
+ }
67
+ };
68
+
69
+ if (docs.length === 0) return null;
70
+
71
+ return (
72
+ <div className="bg-white p-4 rounded-xl shadow-sm border border-slate-200 mb-6 animate-fade-in">
73
+ <div className="flex items-center mb-3">
74
+ <Filter className="w-4 h-4 text-slate-500 mr-2" />
75
+ <h3 className="text-sm font-semibold text-slate-800">Filter Documents</h3>
76
+ <span className="ml-auto text-xs text-slate-500">{docs.length} total docs</span>
77
+ </div>
78
+
79
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
80
+
81
+ {/* Type Filter */}
82
+ <div>
83
+ <div className="flex justify-between items-center mb-2">
84
+ <label className="text-xs font-medium text-slate-600 uppercase tracking-wider">Type</label>
85
+ <button
86
+ onClick={() => toggleAll(allTypes, selectedTypes, setSelectedTypes)}
87
+ className="text-[10px] text-blue-600 hover:text-blue-800"
88
+ >
89
+ {selectedTypes.length === allTypes.length ? 'Clear' : 'All'}
90
+ </button>
91
+ </div>
92
+ <div className="max-h-32 overflow-y-auto custom-scrollbar space-y-1">
93
+ {allTypes.map(type => (
94
+ <label key={type} className="flex items-center space-x-2 cursor-pointer hover:bg-slate-50 p-1 rounded">
95
+ <input
96
+ type="checkbox"
97
+ checked={selectedTypes.includes(type)}
98
+ onChange={() => toggleSelection(type, selectedTypes, setSelectedTypes)}
99
+ className="rounded border-slate-300 text-blue-600 focus:ring-blue-500 h-3.5 w-3.5"
100
+ />
101
+ <span className="text-xs text-slate-700 truncate" title={type}>{type}</span>
102
+ </label>
103
+ ))}
104
+ </div>
105
+ </div>
106
+
107
+ {/* Status Filter */}
108
+ <div>
109
+ <div className="flex justify-between items-center mb-2">
110
+ <label className="text-xs font-medium text-slate-600 uppercase tracking-wider">Status</label>
111
+ <button
112
+ onClick={() => toggleAll(allStatuses, selectedStatuses, setSelectedStatuses)}
113
+ className="text-[10px] text-blue-600 hover:text-blue-800"
114
+ >
115
+ {selectedStatuses.length === allStatuses.length ? 'Clear' : 'All'}
116
+ </button>
117
+ </div>
118
+ <div className="max-h-32 overflow-y-auto custom-scrollbar space-y-1">
119
+ {allStatuses.map(status => (
120
+ <label key={status} className="flex items-center space-x-2 cursor-pointer hover:bg-slate-50 p-1 rounded">
121
+ <input
122
+ type="checkbox"
123
+ checked={selectedStatuses.includes(status)}
124
+ onChange={() => toggleSelection(status, selectedStatuses, setSelectedStatuses)}
125
+ className="rounded border-slate-300 text-blue-600 focus:ring-blue-500 h-3.5 w-3.5"
126
+ />
127
+ <span className="text-xs text-slate-700 truncate" title={status}>{status}</span>
128
+ </label>
129
+ ))}
130
+ </div>
131
+ </div>
132
+
133
+ {/* Agenda Filter */}
134
+ <div>
135
+ <div className="flex justify-between items-center mb-2">
136
+ <label className="text-xs font-medium text-slate-600 uppercase tracking-wider">Agenda Item</label>
137
+ <button
138
+ onClick={() => toggleAll(allAgendas, selectedAgendas, setSelectedAgendas)}
139
+ className="text-[10px] text-blue-600 hover:text-blue-800"
140
+ >
141
+ {selectedAgendas.length === allAgendas.length ? 'Clear' : 'All'}
142
+ </button>
143
+ </div>
144
+ <div className="max-h-32 overflow-y-auto custom-scrollbar space-y-1">
145
+ {allAgendas.map(agenda => (
146
+ <label key={agenda} className="flex items-center space-x-2 cursor-pointer hover:bg-slate-50 p-1 rounded">
147
+ <input
148
+ type="checkbox"
149
+ checked={selectedAgendas.includes(agenda)}
150
+ onChange={() => toggleSelection(agenda, selectedAgendas, setSelectedAgendas)}
151
+ className="rounded border-slate-300 text-blue-600 focus:ring-blue-500 h-3.5 w-3.5"
152
+ />
153
+ <span className="text-xs text-slate-700 truncate" title={agenda}>{agenda}</span>
154
+ </label>
155
+ ))}
156
+ </div>
157
+ </div>
158
+
159
+ </div>
160
+ </div>
161
+ );
162
+ };
163
+
164
+ export default DocFilterBar;
components/FileContentCard.tsx ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState } from 'react';
2
+ import { Innovation, Classification } from '../types';
3
+ import { ChevronDown, ChevronUp, Trash2, Check, Zap, FileText } from 'lucide-react';
4
+ import { COLOR_MAP } from '../constants';
5
+
6
+ interface InnovationCardProps {
7
+ innovation: Innovation;
8
+ onClassify: (id: string, classification: Classification) => void;
9
+ }
10
+
11
+ const InnovationCard: React.FC<InnovationCardProps> = ({ innovation, onClassify }) => {
12
+ const [isExpanded, setIsExpanded] = useState(false);
13
+
14
+ return (
15
+ <div
16
+ className={`bg-white rounded-lg shadow-sm border border-slate-200 mb-4 overflow-hidden transition-all duration-200 ${innovation.classification === Classification.DELETE ? 'opacity-50' : ''}`}>
17
+ <div className="p-4">
18
+ <div className="flex justify-between items-start">
19
+ <div className="flex-1 cursor-pointer" onClick={() => setIsExpanded(!isExpanded)}>
20
+ <div className="px-4 pb-4 bg-slate-50 border-t border-slate-100 pt-3 text-sm">
21
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
22
+ <div>
23
+ <p className="font-semibold text-slate-700 mb-1">File name</p>
24
+ <p className="text-slate-600">{innovation.file_name}</p>
25
+ </div>
26
+ {/* <div>
27
+ <p className="font-semibold text-slate-700 mb-1">Innovation Potential</p>
28
+ <p className="text-slate-600">{ }</p>
29
+ </div> */}
30
+ </div>
31
+ </div>
32
+ </div>
33
+
34
+ <div className="flex items-center ml-4">
35
+ <button
36
+ onClick={(e) => {
37
+ e.stopPropagation();
38
+ onClassify(innovation.id, Classification.DELETE);
39
+ }}
40
+ className="text-red-400 hover:text-red-600 p-1 mr-2 text-xs font-medium border border-red-200 rounded px-2"
41
+ >
42
+ Delete
43
+ </button>
44
+ <button
45
+ onClick={() => setIsExpanded(!isExpanded)}
46
+ className="text-slate-400 hover:text-slate-600 p-1"
47
+ >
48
+ {isExpanded ? <ChevronUp size={20} /> : <ChevronDown size={20} />}
49
+ </button>
50
+ </div>
51
+ </div>
52
+ </div>
53
+
54
+ {isExpanded && (
55
+ <div
56
+ className="flex flex-col gap-2 m-2"
57
+ dangerouslySetInnerHTML={{ __html: innovation.answer }}
58
+ />
59
+ )}
60
+ </div>
61
+ );
62
+ };
63
+
64
+ export default InnovationCard;
components/FilterBar.tsx ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+ import { WORKING_GROUPS } from '../constants';
3
+ import { Search, Loader2 } from 'lucide-react';
4
+
5
+ interface FilterBarProps {
6
+ onFetch: (wg: string, meeting: string) => void;
7
+ isFetching: boolean;
8
+ }
9
+
10
+ const FilterBar: React.FC<FilterBarProps> = ({ onFetch, isFetching }) => {
11
+ const [selectedWg, setSelectedWg] = React.useState(WORKING_GROUPS[0]);
12
+ const [meetings, setMeetings] = React.useState<Record<string, string>>({});
13
+ const [selectedMeeting, setSelectedMeeting] = React.useState('');
14
+ const [isLoadingMeetings, setIsLoadingMeetings] = React.useState(false);
15
+
16
+ React.useEffect(() => {
17
+ const fetchMeetings = async () => {
18
+ setIsLoadingMeetings(true);
19
+ try {
20
+ const response = await fetch('https://organizedprogrammers-docxtract.hf.space/docs/get_meetings',
21
+ { method: 'POST', body: JSON.stringify({ "working_group": selectedWg }), headers: { 'Content-Type': 'application/json' } });
22
+ if (response.ok) {
23
+ const data = await response.json();
24
+ if (data.meetings) {
25
+ setMeetings(data.meetings);
26
+ const firstMeetingValue = Object.values(data.meetings)[0] as string;
27
+ if (firstMeetingValue) {
28
+ setSelectedMeeting(firstMeetingValue);
29
+ }
30
+ }
31
+ } else {
32
+ console.error("Failed to fetch meetings");
33
+ }
34
+ } catch (error) {
35
+ console.error("Error fetching meetings:", error);
36
+ } finally {
37
+ setIsLoadingMeetings(false);
38
+ }
39
+ };
40
+
41
+ fetchMeetings();
42
+ }, [selectedWg]);
43
+
44
+ return (
45
+ <div className="bg-white p-6 rounded-xl shadow-sm border border-slate-200 mb-6">
46
+ <div className="grid grid-cols-1 md:grid-cols-12 gap-4 items-end">
47
+
48
+ <div className="md:col-span-3">
49
+ <label className="block text-sm font-medium text-slate-600 mb-1">Working Group</label>
50
+ <div className="relative">
51
+ <select
52
+ value={selectedWg}
53
+ onChange={(e) => setSelectedWg(e.target.value)}
54
+ className="w-full appearance-none bg-slate-50 border border-slate-300 text-slate-700 py-2.5 px-3 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
55
+ >
56
+ {WORKING_GROUPS.map(wg => <option key={wg} value={wg}>{wg}</option>)}
57
+ </select>
58
+ <div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-slate-500">
59
+ <svg className="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z" /></svg>
60
+ </div>
61
+ </div>
62
+ </div>
63
+
64
+ <div className="md:col-span-4">
65
+ <label className="block text-sm font-medium text-slate-600 mb-1">Meeting</label>
66
+ <div className="relative">
67
+ <select
68
+ value={selectedMeeting}
69
+ onChange={(e) => setSelectedMeeting(e.target.value)}
70
+ disabled={isLoadingMeetings}
71
+ className="w-full appearance-none bg-slate-50 border border-slate-300 text-slate-700 py-2.5 px-3 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:opacity-50"
72
+ >
73
+ {isLoadingMeetings ? (
74
+ <option>Loading meetings...</option>
75
+ ) : (
76
+ Object.entries(meetings).map(([displayName, value]) => (
77
+ <option key={value} value={value}>{displayName}</option>
78
+ ))
79
+ )}
80
+ </select>
81
+ <div className="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-slate-500">
82
+ <svg className="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z" /></svg>
83
+ </div>
84
+ </div>
85
+ </div>
86
+
87
+ <div className="md:col-span-3">
88
+ <label className="block text-sm font-medium text-slate-600 mb-2">Doc Types</label>
89
+ <div className="flex space-x-4">
90
+ <label className="inline-flex items-center">
91
+ <input type="checkbox" className="form-checkbox text-blue-600 h-4 w-4 rounded border-slate-300" defaultChecked />
92
+ <span className="ml-2 text-slate-700">CR</span>
93
+ </label>
94
+ <label className="inline-flex items-center">
95
+ <input type="checkbox" className="form-checkbox text-blue-600 h-4 w-4 rounded border-slate-300" defaultChecked />
96
+ <span className="ml-2 text-slate-700">PCR</span>
97
+ </label>
98
+ </div>
99
+ </div>
100
+
101
+ <div className="md:col-span-2">
102
+ <button
103
+ onClick={() => onFetch(selectedWg, selectedMeeting)}
104
+ disabled={isFetching}
105
+ className="w-full flex items-center justify-center bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2.5 px-4 rounded-lg transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
106
+ >
107
+ {isFetching ? (
108
+ <Loader2 className="w-4 h-4 mr-2 animate-spin" />
109
+ ) : (
110
+ <Search className="w-4 h-4 mr-2" />
111
+ )}
112
+ Fetch Docs
113
+ </button>
114
+ </div>
115
+
116
+ </div>
117
+ </div>
118
+ );
119
+ };
120
+
121
+ export default FilterBar;
components/InnovationCard.tsx ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState } from 'react';
2
+ import { Innovation, Classification, ResultResponse } from '../types';
3
+ import { ChevronDown, ChevronUp, Trash2, Check, Zap, FileText } from 'lucide-react';
4
+ import { COLOR_MAP } from '../constants';
5
+
6
+ interface InnovationCardProps {
7
+ innovation: ResultResponse;
8
+ onClassify: (id: string, classification: Classification) => void;
9
+ }
10
+
11
+ const InnovationCard: React.FC<InnovationCardProps> = ({ innovation, onClassify }) => {
12
+ const [isExpanded, setIsExpanded] = useState(false);
13
+
14
+ const getBorderColor = (cls: Classification) => {
15
+ return cls === Classification.UNCLASSIFIED ? 'border-l-4 border-l-slate-300' : `border-l-4 border-l-[${COLOR_MAP[cls]}]`;
16
+ };
17
+
18
+ // Inline style for border color since Tailwind arbitrary values in template literals can be tricky
19
+ const borderStyle = { borderLeftColor: COLOR_MAP[innovation.classification] };
20
+
21
+ // Extraction Logic
22
+ console.log(innovation)
23
+ const contextText = innovation.context;
24
+ const problemText = innovation.problem;
25
+
26
+ return (
27
+ <div
28
+ className={`bg-white rounded-lg shadow-sm border border-slate-200 mb-4 overflow-hidden transition-all duration-200 ${innovation.classification === Classification.DELETE ? 'opacity-50' : ''}`}
29
+ style={borderStyle}
30
+ >
31
+ <div className="p-4">
32
+ <div className="flex justify-between items-start">
33
+ <div className="flex-1 cursor-pointer" onClick={() => setIsExpanded(!isExpanded)}>
34
+ <div className="px-4 pb-4 bg-slate-50 border-t border-slate-100 pt-3 text-sm">
35
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
36
+ <div>
37
+ <p className="font-semibold text-slate-700 mb-1">Context</p>
38
+ <p className="text-slate-600 text-xs">{contextText}</p>
39
+ </div>
40
+ <div>
41
+ <p className="font-semibold text-slate-700 mb-1">Problem Description</p>
42
+ <p className="text-slate-600 text-xs">{problemText}</p>
43
+ </div>
44
+ </div>
45
+ </div>
46
+ </div>
47
+
48
+ <button
49
+ onClick={() => setIsExpanded(!isExpanded)}
50
+ className="ml-4 text-slate-400 hover:text-slate-600 p-1"
51
+ >
52
+ {isExpanded ? <ChevronUp size={20} /> : <ChevronDown size={20} />}
53
+ </button>
54
+ </div>
55
+
56
+ {/* Quick Actions (Always visible) */}
57
+ <div className="mt-4 flex gap-2 border-t border-slate-100 pt-3">
58
+ <button
59
+ onClick={() => onClassify(innovation.id.toString(), Classification.DELETE)}
60
+ className={`flex-1 flex items-center justify-center px-3 py-1.5 text-xs font-medium rounded transition-colors ${innovation.classification === Classification.DELETE ? 'bg-slate-800 text-white' : 'bg-slate-50 text-slate-600 hover:bg-slate-100'}`}
61
+ >
62
+ <Trash2 className="w-3 h-3 mr-1.5" /> Delete
63
+ </button>
64
+ <button
65
+ onClick={() => onClassify(innovation.id.toString(), Classification.LOW)}
66
+ className={`flex-1 flex items-center justify-center px-3 py-1.5 text-xs font-medium rounded transition-colors ${innovation.classification === Classification.LOW ? 'bg-blue-600 text-white' : 'bg-blue-50 text-blue-700 hover:bg-blue-100'}`}
67
+ >
68
+ Low
69
+ </button>
70
+ <button
71
+ onClick={() => onClassify(innovation.id.toString(), Classification.MEDIUM)}
72
+ className={`flex-1 flex items-center justify-center px-3 py-1.5 text-xs font-medium rounded transition-colors ${innovation.classification === Classification.MEDIUM ? 'bg-yellow-500 text-white' : 'bg-yellow-50 text-yellow-700 hover:bg-yellow-100'}`}
73
+ >
74
+ Medium
75
+ </button>
76
+ <button
77
+ onClick={() => onClassify(innovation.id.toString(), Classification.HIGH)}
78
+ className={`flex-1 flex items-center justify-center px-3 py-1.5 text-xs font-medium rounded transition-colors ${innovation.classification === Classification.HIGH ? 'bg-green-600 text-white' : 'bg-green-50 text-green-700 hover:bg-green-100'}`}
79
+ >
80
+ <Zap className="w-3 h-3 mr-1.5" /> High
81
+ </button>
82
+ </div>
83
+ </div>
84
+
85
+ {isExpanded && (
86
+ <div
87
+ className="flex flex-col gap-2 m-2"
88
+ dangerouslySetInnerHTML={{ __html: innovation.content }}
89
+ />
90
+ )}
91
+ </div>
92
+ );
93
+ };
94
+
95
+ export default InnovationCard;
components/StatsDashboard.tsx ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useEffect, useState } from 'react';
2
+ import { PieChart, Pie, Cell, ResponsiveContainer, BarChart, Bar, XAxis, YAxis, Tooltip, Legend } from 'recharts';
3
+ import { Classification, Innovation, StatsData, ResultResponse } from '../types';
4
+ import { COLOR_MAP } from '../constants';
5
+ import { backendService } from '../services/backendService';
6
+ import InnovationCard from './InnovationCard';
7
+ import { CircleDashed } from 'lucide-react';
8
+
9
+ interface StatsDashboardProps {
10
+ innovations: Innovation[];
11
+ isVisible: boolean;
12
+ }
13
+
14
+ const StatsDashboard: React.FC<StatsDashboardProps> = ({ isVisible }) => {
15
+ const [dbInnovations, setDbInnovations] = useState<ResultResponse[]>([]);
16
+ const [loading, setLoading] = useState(false);
17
+
18
+ // Fetch from DB for the "True" state
19
+ const fetchDbInnovations = async () => {
20
+ setLoading(true);
21
+ const results = await backendService.fetchClassifiedInnovations();
22
+
23
+ // Transform ResultResponse -> Innovation
24
+ const transformed: ResultResponse[] = results.map((r: any) => ({
25
+ id: r.id,
26
+ file_name: r.file_name,
27
+ content: r.content,
28
+ context: r.context || "N/A",
29
+ problem: r.problem || "N/A",
30
+ methodology: r.methodology || "N/A",
31
+ classification: r.classification,
32
+ }));
33
+
34
+ setDbInnovations(transformed);
35
+ setLoading(false);
36
+ };
37
+
38
+ useEffect(() => {
39
+ if (isVisible) {
40
+ fetchDbInnovations();
41
+ }
42
+ }, [isVisible]);
43
+
44
+
45
+ const handleClassify = async (id: string, classification: Classification) => {
46
+ // Find the innovation
47
+ const inv = dbInnovations.find(i => i.id === Number(id));
48
+ if (inv && inv.id) {
49
+ // Optimistic update
50
+ setDbInnovations(prev => prev.map(i => i.id === Number(id) ? { ...i, classification } : i));
51
+ await backendService.saveClassification(Number(id), classification);
52
+ }
53
+ };
54
+
55
+ // Filter for Display (High, Medium, Low, Unclassified)
56
+ const displayInnovations = dbInnovations.filter(i =>
57
+ [Classification.HIGH, Classification.MEDIUM, Classification.LOW, Classification.UNCLASSIFIED].includes(i.classification as Classification)
58
+ );
59
+
60
+ // Stats Logic - Use DB data for charts to be consistent with the list below
61
+ const statsSource = dbInnovations.length > 0 ? dbInnovations : [];
62
+
63
+ const data: StatsData[] = [
64
+ { name: 'High Priority', value: statsSource.filter(i => i.classification === Classification.HIGH).length, fill: COLOR_MAP[Classification.HIGH] },
65
+ { name: 'Medium Priority', value: statsSource.filter(i => i.classification === Classification.MEDIUM).length, fill: COLOR_MAP[Classification.MEDIUM] },
66
+ { name: 'Low Priority', value: statsSource.filter(i => i.classification === Classification.LOW).length, fill: COLOR_MAP[Classification.LOW] },
67
+ { name: 'Rejected', value: statsSource.filter(i => i.classification === Classification.DELETE).length, fill: COLOR_MAP[Classification.DELETE] },
68
+ { name: 'Unclassified', value: statsSource.filter(i => i.classification === Classification.UNCLASSIFIED).length, fill: COLOR_MAP[Classification.UNCLASSIFIED] },
69
+ ];
70
+
71
+ // Mock context data (unchanged)
72
+ const contextData = [
73
+ { name: 'Network Opt', count: 12 },
74
+ { name: 'Security', count: 8 },
75
+ { name: 'QoS', count: 15 },
76
+ { name: 'New Use Cases', count: 5 },
77
+ ];
78
+
79
+ return (
80
+ <div className="space-y-8">
81
+ {/* Charts Section */}
82
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
83
+ <div className="bg-white p-6 rounded-lg shadow-sm border border-slate-200">
84
+ <h3 className="text-lg font-semibold text-slate-800 mb-4">Classification Status</h3>
85
+ <div className="h-64">
86
+ <ResponsiveContainer width="100%" height="100%">
87
+ <PieChart>
88
+ <Pie
89
+ data={data}
90
+ cx="50%"
91
+ cy="50%"
92
+ innerRadius={60}
93
+ outerRadius={80}
94
+ paddingAngle={5}
95
+ dataKey="value"
96
+ >
97
+ {data.map((entry, index) => (
98
+ <Cell key={`cell-${index}`} fill={entry.fill} />
99
+ ))}
100
+ </Pie>
101
+ <Tooltip />
102
+ <Legend />
103
+ </PieChart>
104
+ </ResponsiveContainer>
105
+ </div>
106
+ </div>
107
+
108
+ <div className="bg-white p-6 rounded-lg shadow-sm border border-slate-200">
109
+ <h3 className="text-lg font-semibold text-slate-800 mb-4">Innovation Contexts (Trends)</h3>
110
+ <div className="h-64">
111
+ <ResponsiveContainer width="100%" height="100%">
112
+ <BarChart data={contextData}>
113
+ <XAxis dataKey="name" fontSize={12} tickLine={false} axisLine={false} />
114
+ <YAxis hide />
115
+ <Tooltip cursor={{ fill: 'transparent' }} />
116
+ <Bar dataKey="count" fill="#3b82f6" radius={[4, 4, 0, 0]} />
117
+ </BarChart>
118
+ </ResponsiveContainer>
119
+ </div>
120
+ </div>
121
+ </div>
122
+
123
+ {/* Classified List Section */}
124
+ <div className="bg-white p-6 rounded-lg shadow-sm border border-slate-200">
125
+ <div className="flex items-center justify-between mb-6">
126
+ <h3 className="text-lg font-semibold text-slate-800">Classified Innovations</h3>
127
+ <button onClick={fetchDbInnovations} className="text-sm text-slate-500 hover:text-blue-600 flex items-center">
128
+ {loading && <CircleDashed className="w-4 h-4 mr-1 animate-spin" />}
129
+ Refresh
130
+ </button>
131
+ </div>
132
+
133
+ {displayInnovations.length === 0 ? (
134
+ <p className="text-center text-slate-500 py-8">No items (High, Medium, Low, Unclassified) found.</p>
135
+ ) : (
136
+ <div className="space-y-4">
137
+ {displayInnovations.map(inv => (
138
+ <InnovationCard
139
+ key={inv.id}
140
+ innovation={inv}
141
+ onClassify={handleClassify}
142
+ />
143
+ ))}
144
+ </div>
145
+ )}
146
+ </div>
147
+ </div>
148
+ );
149
+ };
150
+
151
+ export default StatsDashboard;
constants.ts ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Innovation, Classification } from './types';
2
+
3
+ export const WORKING_GROUPS = ['SA1', 'SA2', 'SA3', 'SA4', 'SA5', 'SA6', 'RAN1', 'RAN2'];
4
+ export const MEETINGS = ['Dallas (Nov 2024)', 'Maastricht (Aug 2024)', 'Jeju (May 2024)', 'Athens (Feb 2024)'];
5
+
6
+ export const MOCK_INNOVATIONS_POOL: Omit<Innovation, 'id' | 'batch_id' | 'classification'>[] = [
7
+ {
8
+ problem_id: "CP-882",
9
+ context: "Satellite integration in 5G Non-Terrestrial Networks (NTN)",
10
+ problem_statement: "High latency variations in LEO satellite constellations cause handover failures during fast UE movement.",
11
+ innovation_potential: "Proposes a predictive QoS-based handover trigger that utilizes satellite ephemeris data to pre-allocate resources.",
12
+ source_reference: "TR 38.821 Sec 4.2",
13
+ },
14
+ {
15
+ problem_id: "CP-901",
16
+ context: "XR/VR Traffic handling in RAN",
17
+ problem_statement: "Current semi-persistent scheduling (SPS) does not account for jitter inherent in cloud-rendered VR frames.",
18
+ innovation_potential: "Introduces a frame-aware scheduling buffer that aligns grants with application-layer frame boundaries.",
19
+ source_reference: "TS 38.300 Sec 12",
20
+ },
21
+ {
22
+ problem_id: "CP-112",
23
+ context: "Sidelink positioning for V2X",
24
+ problem_statement: "GPS unavailability in urban canyons degrades V2X safety application reliability.",
25
+ innovation_potential: "Utilizes cooperative ranging between vehicles using relative signal strength and RTT to establish local relative positioning.",
26
+ source_reference: "TR 38.885 Sec 6.1",
27
+ },
28
+ {
29
+ problem_id: "CP-445",
30
+ context: "Network Energy Saving",
31
+ problem_statement: "Sleep mode transitions for gNBs are too slow to react to bursty IoT traffic.",
32
+ innovation_potential: "AI-driven traffic prediction model resident at the DU to trigger micro-sleep states.",
33
+ source_reference: "TS 28.310 Sec 5",
34
+ },
35
+ ];
36
+
37
+ export const COLOR_MAP: Record<Classification, string> = {
38
+ [Classification.UNCLASSIFIED]: '#94a3b8',
39
+ [Classification.DELETE]: '#ef4444',
40
+ [Classification.LOW]: '#3b82f6',
41
+ [Classification.MEDIUM]: '#eab308',
42
+ [Classification.HIGH]: '#22c55e',
43
+ };
index.html ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>3GPP Innovation Extractor</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script type="importmap">
9
+ {
10
+ "imports": {
11
+ "react": "https://aistudiocdn.com/react@^19.2.0",
12
+ "react/": "https://aistudiocdn.com/react@^19.2.0/",
13
+ "react-dom/": "https://aistudiocdn.com/react-dom@^19.2.0/",
14
+ "lucide-react": "https://aistudiocdn.com/lucide-react@^0.555.0",
15
+ "recharts": "https://aistudiocdn.com/recharts@^3.5.0"
16
+ }
17
+ }
18
+ </script>
19
+ <link rel="stylesheet" href="/index.css">
20
+ </head>
21
+ <body>
22
+ <div id="root"></div>
23
+ <script type="module" src="/index.tsx"></script>
24
+ </body>
25
+ </html>
index.tsx ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom/client';
3
+ import App from './App';
4
+
5
+ const rootElement = document.getElementById('root');
6
+ if (!rootElement) {
7
+ throw new Error("Could not find root element to mount to");
8
+ }
9
+
10
+ const root = ReactDOM.createRoot(rootElement);
11
+ root.render(
12
+ <React.StrictMode>
13
+ <App />
14
+ </React.StrictMode>
15
+ );
metadata.json ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ {
2
+ "name": "3GPP Innovation Extractor",
3
+ "description": "A React application for extracting and classifying innovation context-problems from 3GPP documents using Open Notebook architecture.",
4
+ "requestFramePermissions": []
5
+ }
openapi.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"openapi":"3.1.0","info":{"title":"Open Notebook API","description":"API for Open Notebook - Research Assistant","version":"0.2.2"},"paths":{"/api/auth/status":{"get":{"tags":["auth","auth"],"summary":"Get Auth Status","description":"Check if authentication is enabled.\nReturns whether a password is required to access the API.","operationId":"get_auth_status_api_auth_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/config":{"get":{"tags":["config"],"summary":"Get Config","description":"Get frontend configuration.\n\nReturns version information and health status.\nNote: The frontend determines the API URL via its own runtime-config endpoint,\nso this endpoint no longer returns apiUrl.\n\nAlso checks for version updates from GitHub (with caching and error handling).","operationId":"get_config_api_config_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/notebooks":{"get":{"tags":["notebooks"],"summary":"Get Notebooks","description":"Get all notebooks with optional filtering and ordering.","operationId":"get_notebooks_api_notebooks_get","parameters":[{"name":"archived","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Filter by archived status","title":"Archived"},"description":"Filter by archived status"},{"name":"order_by","in":"query","required":false,"schema":{"type":"string","description":"Order by field and direction","default":"updated desc","title":"Order By"},"description":"Order by field and direction"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NotebookResponse"},"title":"Response Get Notebooks Api Notebooks Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["notebooks"],"summary":"Create Notebook","description":"Create a new notebook.","operationId":"create_notebook_api_notebooks_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotebookCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotebookResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/notebooks/{notebook_id}":{"get":{"tags":["notebooks"],"summary":"Get Notebook","description":"Get a specific notebook by ID.","operationId":"get_notebook_api_notebooks__notebook_id__get","parameters":[{"name":"notebook_id","in":"path","required":true,"schema":{"type":"string","title":"Notebook Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotebookResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["notebooks"],"summary":"Update Notebook","description":"Update a notebook.","operationId":"update_notebook_api_notebooks__notebook_id__put","parameters":[{"name":"notebook_id","in":"path","required":true,"schema":{"type":"string","title":"Notebook Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotebookUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotebookResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["notebooks"],"summary":"Delete Notebook","description":"Delete a notebook.","operationId":"delete_notebook_api_notebooks__notebook_id__delete","parameters":[{"name":"notebook_id","in":"path","required":true,"schema":{"type":"string","title":"Notebook Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/notebooks/{notebook_id}/sources/{source_id}":{"post":{"tags":["notebooks"],"summary":"Add Source To Notebook","description":"Add an existing source to a notebook (create the reference).","operationId":"add_source_to_notebook_api_notebooks__notebook_id__sources__source_id__post","parameters":[{"name":"notebook_id","in":"path","required":true,"schema":{"type":"string","title":"Notebook Id"}},{"name":"source_id","in":"path","required":true,"schema":{"type":"string","title":"Source Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["notebooks"],"summary":"Remove Source From Notebook","description":"Remove a source from a notebook (delete the reference).","operationId":"remove_source_from_notebook_api_notebooks__notebook_id__sources__source_id__delete","parameters":[{"name":"notebook_id","in":"path","required":true,"schema":{"type":"string","title":"Notebook Id"}},{"name":"source_id","in":"path","required":true,"schema":{"type":"string","title":"Source Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/search":{"post":{"tags":["search"],"summary":"Search Knowledge Base","description":"Search the knowledge base using text or vector search.","operationId":"search_knowledge_base_api_search_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/search/ask":{"post":{"tags":["search"],"summary":"Ask Knowledge Base","description":"Ask the knowledge base a question using AI models.","operationId":"ask_knowledge_base_api_search_ask_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AskRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/search/ask/simple":{"post":{"tags":["search"],"summary":"Ask Knowledge Base Simple","description":"Ask the knowledge base a question and return a simple response (non-streaming).","operationId":"ask_knowledge_base_simple_api_search_ask_simple_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AskRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AskResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/models":{"get":{"tags":["models"],"summary":"Get Models","description":"Get all configured models with optional type filtering.","operationId":"get_models_api_models_get","parameters":[{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by model type","title":"Type"},"description":"Filter by model type"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ModelResponse"},"title":"Response Get Models Api Models Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["models"],"summary":"Create Model","description":"Create a new model configuration.","operationId":"create_model_api_models_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/models/{model_id}":{"delete":{"tags":["models"],"summary":"Delete Model","description":"Delete a model configuration.","operationId":"delete_model_api_models__model_id__delete","parameters":[{"name":"model_id","in":"path","required":true,"schema":{"type":"string","title":"Model Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/models/defaults":{"get":{"tags":["models"],"summary":"Get Default Models","description":"Get default model assignments.","operationId":"get_default_models_api_models_defaults_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DefaultModelsResponse"}}}}}},"put":{"tags":["models"],"summary":"Update Default Models","description":"Update default model assignments.","operationId":"update_default_models_api_models_defaults_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DefaultModelsResponse"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DefaultModelsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/models/providers":{"get":{"tags":["models"],"summary":"Get Provider Availability","description":"Get provider availability based on environment variables.","operationId":"get_provider_availability_api_models_providers_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProviderAvailabilityResponse"}}}}}}},"/api/transformations":{"get":{"tags":["transformations"],"summary":"Get Transformations","description":"Get all transformations.","operationId":"get_transformations_api_transformations_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/TransformationResponse"},"type":"array","title":"Response Get Transformations Api Transformations Get"}}}}}},"post":{"tags":["transformations"],"summary":"Create Transformation","description":"Create a new transformation.","operationId":"create_transformation_api_transformations_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransformationCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransformationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/transformations/execute":{"post":{"tags":["transformations"],"summary":"Execute Transformation","description":"Execute a transformation on input text.","operationId":"execute_transformation_api_transformations_execute_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransformationExecuteRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransformationExecuteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/transformations/default-prompt":{"get":{"tags":["transformations"],"summary":"Get Default Prompt","description":"Get the default transformation prompt.","operationId":"get_default_prompt_api_transformations_default_prompt_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DefaultPromptResponse"}}}}}},"put":{"tags":["transformations"],"summary":"Update Default Prompt","description":"Update the default transformation prompt.","operationId":"update_default_prompt_api_transformations_default_prompt_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DefaultPromptUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DefaultPromptResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/transformations/{transformation_id}":{"get":{"tags":["transformations"],"summary":"Get Transformation","description":"Get a specific transformation by ID.","operationId":"get_transformation_api_transformations__transformation_id__get","parameters":[{"name":"transformation_id","in":"path","required":true,"schema":{"type":"string","title":"Transformation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransformationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["transformations"],"summary":"Update Transformation","description":"Update a transformation.","operationId":"update_transformation_api_transformations__transformation_id__put","parameters":[{"name":"transformation_id","in":"path","required":true,"schema":{"type":"string","title":"Transformation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransformationUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransformationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["transformations"],"summary":"Delete Transformation","description":"Delete a transformation.","operationId":"delete_transformation_api_transformations__transformation_id__delete","parameters":[{"name":"transformation_id","in":"path","required":true,"schema":{"type":"string","title":"Transformation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/notes":{"get":{"tags":["notes"],"summary":"Get Notes","description":"Get all notes with optional notebook filtering.","operationId":"get_notes_api_notes_get","parameters":[{"name":"notebook_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by notebook ID","title":"Notebook Id"},"description":"Filter by notebook ID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NoteResponse"},"title":"Response Get Notes Api Notes Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["notes"],"summary":"Create Note","description":"Create a new note.","operationId":"create_note_api_notes_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/notes/{note_id}":{"get":{"tags":["notes"],"summary":"Get Note","description":"Get a specific note by ID.","operationId":"get_note_api_notes__note_id__get","parameters":[{"name":"note_id","in":"path","required":true,"schema":{"type":"string","title":"Note Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["notes"],"summary":"Update Note","description":"Update a note.","operationId":"update_note_api_notes__note_id__put","parameters":[{"name":"note_id","in":"path","required":true,"schema":{"type":"string","title":"Note Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["notes"],"summary":"Delete Note","description":"Delete a note.","operationId":"delete_note_api_notes__note_id__delete","parameters":[{"name":"note_id","in":"path","required":true,"schema":{"type":"string","title":"Note Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/embed":{"post":{"tags":["embedding"],"summary":"Embed Content","description":"Embed content for vector search.","operationId":"embed_content_api_embed_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbedRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbedResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/embeddings/rebuild":{"post":{"tags":["embeddings"],"summary":"Start Rebuild","description":"Start a background job to rebuild embeddings.\n\n- **mode**: \"existing\" (re-embed items with embeddings) or \"all\" (embed everything)\n- **include_sources**: Include sources in rebuild (default: true)\n- **include_notes**: Include notes in rebuild (default: true)\n- **include_insights**: Include insights in rebuild (default: true)\n\nReturns command ID to track progress and estimated item count.","operationId":"start_rebuild_api_embeddings_rebuild_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RebuildRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RebuildResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/embeddings/rebuild/{command_id}/status":{"get":{"tags":["embeddings"],"summary":"Get Rebuild Status","description":"Get the status of a rebuild operation.\n\nReturns:\n- **status**: queued, running, completed, failed\n- **progress**: processed count, total count, percentage\n- **stats**: breakdown by type (sources, notes, insights, failed)\n- **timestamps**: started_at, completed_at","operationId":"get_rebuild_status_api_embeddings_rebuild__command_id__status_get","parameters":[{"name":"command_id","in":"path","required":true,"schema":{"type":"string","title":"Command Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RebuildStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/settings":{"get":{"tags":["settings"],"summary":"Get Settings","description":"Get all application settings.","operationId":"get_settings_api_settings_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsResponse"}}}}}},"put":{"tags":["settings"],"summary":"Update Settings","description":"Update application settings.","operationId":"update_settings_api_settings_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/notebooks/{notebook_id}/context":{"post":{"tags":["context"],"summary":"Get Notebook Context","description":"Get context for a notebook based on configuration.","operationId":"get_notebook_context_api_notebooks__notebook_id__context_post","parameters":[{"name":"notebook_id","in":"path","required":true,"schema":{"type":"string","title":"Notebook Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContextRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContextResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sources":{"get":{"tags":["sources"],"summary":"Get Sources","description":"Get sources with pagination and sorting support.","operationId":"get_sources_api_sources_get","parameters":[{"name":"notebook_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by notebook ID","title":"Notebook Id"},"description":"Filter by notebook ID"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"description":"Number of sources to return (1-100)","default":50,"title":"Limit"},"description":"Number of sources to return (1-100)"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Number of sources to skip","default":0,"title":"Offset"},"description":"Number of sources to skip"},{"name":"sort_by","in":"query","required":false,"schema":{"type":"string","description":"Field to sort by (created or updated)","default":"updated","title":"Sort By"},"description":"Field to sort by (created or updated)"},{"name":"sort_order","in":"query","required":false,"schema":{"type":"string","description":"Sort order (asc or desc)","default":"desc","title":"Sort Order"},"description":"Sort order (asc or desc)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SourceListResponse"},"title":"Response Get Sources Api Sources Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["sources"],"summary":"Create Source","description":"Create a new source with support for both JSON and multipart form data.","operationId":"create_source_api_sources_post","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_create_source_api_sources_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sources/json":{"post":{"tags":["sources"],"summary":"Create Source Json","description":"Create a new source using JSON payload (legacy endpoint for backward compatibility).","operationId":"create_source_json_api_sources_json_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sources/{source_id}":{"get":{"tags":["sources"],"summary":"Get Source","description":"Get a specific source by ID.","operationId":"get_source_api_sources__source_id__get","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"string","title":"Source Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["sources"],"summary":"Update Source","description":"Update a source.","operationId":"update_source_api_sources__source_id__put","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"string","title":"Source Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["sources"],"summary":"Delete Source","description":"Delete a source.","operationId":"delete_source_api_sources__source_id__delete","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"string","title":"Source Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sources/{source_id}/download":{"head":{"tags":["sources"],"summary":"Check Source File","description":"Check if a source has a downloadable file.","operationId":"check_source_file_api_sources__source_id__download_head","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"string","title":"Source Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["sources"],"summary":"Download Source File","description":"Download the original file associated with an uploaded source.","operationId":"download_source_file_api_sources__source_id__download_get","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"string","title":"Source Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sources/{source_id}/status":{"get":{"tags":["sources"],"summary":"Get Source Status","description":"Get processing status for a source.","operationId":"get_source_status_api_sources__source_id__status_get","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"string","title":"Source Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sources/{source_id}/retry":{"post":{"tags":["sources"],"summary":"Retry Source Processing","description":"Retry processing for a failed or stuck source.","operationId":"retry_source_processing_api_sources__source_id__retry_post","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"string","title":"Source Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sources/{source_id}/insights":{"get":{"tags":["sources"],"summary":"Get Source Insights","description":"Get all insights for a specific source.","operationId":"get_source_insights_api_sources__source_id__insights_get","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"string","title":"Source Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SourceInsightResponse"},"title":"Response Get Source Insights Api Sources Source Id Insights Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["sources"],"summary":"Create Source Insight","description":"Create a new insight for a source by running a transformation.","operationId":"create_source_insight_api_sources__source_id__insights_post","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"string","title":"Source Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSourceInsightRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceInsightResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/insights/{insight_id}":{"get":{"tags":["insights"],"summary":"Get Insight","description":"Get a specific insight by ID.","operationId":"get_insight_api_insights__insight_id__get","parameters":[{"name":"insight_id","in":"path","required":true,"schema":{"type":"string","title":"Insight Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceInsightResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["insights"],"summary":"Delete Insight","description":"Delete a specific insight.","operationId":"delete_insight_api_insights__insight_id__delete","parameters":[{"name":"insight_id","in":"path","required":true,"schema":{"type":"string","title":"Insight Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/insights/{insight_id}/save-as-note":{"post":{"tags":["insights"],"summary":"Save Insight As Note","description":"Convert an insight to a note.","operationId":"save_insight_as_note_api_insights__insight_id__save_as_note_post","parameters":[{"name":"insight_id","in":"path","required":true,"schema":{"type":"string","title":"Insight Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveAsNoteRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NoteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/commands/jobs":{"post":{"tags":["commands"],"summary":"Execute Command","description":"Submit a command for background processing.\nReturns immediately with job ID for status tracking.\n\nExample request:\n{\n \"command\": \"process_text\",\n \"app\": \"open_notebook\", \n \"input\": { \n \"text\": \"Hello world\", \n \"operation\": \"uppercase\" \n }\n}","operationId":"execute_command_api_commands_jobs_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommandExecutionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommandJobResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["commands"],"summary":"List Command Jobs","description":"List command jobs with optional filtering","operationId":"list_command_jobs_api_commands_jobs_get","parameters":[{"name":"command_filter","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by command name","title":"Command Filter"},"description":"Filter by command name"},{"name":"status_filter","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter by status","title":"Status Filter"},"description":"Filter by status"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","description":"Maximum number of jobs to return","default":50,"title":"Limit"},"description":"Maximum number of jobs to return"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true},"title":"Response List Command Jobs Api Commands Jobs Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/commands/jobs/{job_id}":{"get":{"tags":["commands"],"summary":"Get Command Job Status","description":"Get the status of a specific command job","operationId":"get_command_job_status_api_commands_jobs__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommandJobStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["commands"],"summary":"Cancel Command Job","description":"Cancel a running command job","operationId":"cancel_command_job_api_commands_jobs__job_id__delete","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/commands/registry/debug":{"get":{"tags":["commands"],"summary":"Debug Registry","description":"Debug endpoint to see what commands are registered","operationId":"debug_registry_api_commands_registry_debug_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/podcasts/generate":{"post":{"tags":["podcasts"],"summary":"Generate Podcast","description":"Generate a podcast episode using Episode Profiles.\nReturns immediately with job ID for status tracking.","operationId":"generate_podcast_api_podcasts_generate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PodcastGenerationRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PodcastGenerationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/podcasts/jobs/{job_id}":{"get":{"tags":["podcasts"],"summary":"Get Podcast Job Status","description":"Get the status of a podcast generation job","operationId":"get_podcast_job_status_api_podcasts_jobs__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/podcasts/episodes":{"get":{"tags":["podcasts"],"summary":"List Podcast Episodes","description":"List all podcast episodes","operationId":"list_podcast_episodes_api_podcasts_episodes_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/PodcastEpisodeResponse"},"type":"array","title":"Response List Podcast Episodes Api Podcasts Episodes Get"}}}}}}},"/api/podcasts/episodes/{episode_id}":{"get":{"tags":["podcasts"],"summary":"Get Podcast Episode","description":"Get a specific podcast episode","operationId":"get_podcast_episode_api_podcasts_episodes__episode_id__get","parameters":[{"name":"episode_id","in":"path","required":true,"schema":{"type":"string","title":"Episode Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PodcastEpisodeResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["podcasts"],"summary":"Delete Podcast Episode","description":"Delete a podcast episode and its associated audio file","operationId":"delete_podcast_episode_api_podcasts_episodes__episode_id__delete","parameters":[{"name":"episode_id","in":"path","required":true,"schema":{"type":"string","title":"Episode Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/podcasts/episodes/{episode_id}/audio":{"get":{"tags":["podcasts"],"summary":"Stream Podcast Episode Audio","description":"Stream the audio file associated with a podcast episode","operationId":"stream_podcast_episode_audio_api_podcasts_episodes__episode_id__audio_get","parameters":[{"name":"episode_id","in":"path","required":true,"schema":{"type":"string","title":"Episode Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/episode-profiles":{"get":{"tags":["episode-profiles"],"summary":"List Episode Profiles","description":"List all available episode profiles","operationId":"list_episode_profiles_api_episode_profiles_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/EpisodeProfileResponse"},"type":"array","title":"Response List Episode Profiles Api Episode Profiles Get"}}}}}},"post":{"tags":["episode-profiles"],"summary":"Create Episode Profile","description":"Create a new episode profile","operationId":"create_episode_profile_api_episode_profiles_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EpisodeProfileCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EpisodeProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/episode-profiles/{profile_name}":{"get":{"tags":["episode-profiles"],"summary":"Get Episode Profile","description":"Get a specific episode profile by name","operationId":"get_episode_profile_api_episode_profiles__profile_name__get","parameters":[{"name":"profile_name","in":"path","required":true,"schema":{"type":"string","title":"Profile Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EpisodeProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/episode-profiles/{profile_id}":{"put":{"tags":["episode-profiles"],"summary":"Update Episode Profile","description":"Update an existing episode profile","operationId":"update_episode_profile_api_episode_profiles__profile_id__put","parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"string","title":"Profile Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EpisodeProfileCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EpisodeProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["episode-profiles"],"summary":"Delete Episode Profile","description":"Delete an episode profile","operationId":"delete_episode_profile_api_episode_profiles__profile_id__delete","parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"string","title":"Profile Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/episode-profiles/{profile_id}/duplicate":{"post":{"tags":["episode-profiles"],"summary":"Duplicate Episode Profile","description":"Duplicate an episode profile","operationId":"duplicate_episode_profile_api_episode_profiles__profile_id__duplicate_post","parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"string","title":"Profile Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EpisodeProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/speaker-profiles":{"get":{"tags":["speaker-profiles"],"summary":"List Speaker Profiles","description":"List all available speaker profiles","operationId":"list_speaker_profiles_api_speaker_profiles_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/SpeakerProfileResponse"},"type":"array","title":"Response List Speaker Profiles Api Speaker Profiles Get"}}}}}},"post":{"tags":["speaker-profiles"],"summary":"Create Speaker Profile","description":"Create a new speaker profile","operationId":"create_speaker_profile_api_speaker_profiles_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeakerProfileCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeakerProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/speaker-profiles/{profile_name}":{"get":{"tags":["speaker-profiles"],"summary":"Get Speaker Profile","description":"Get a specific speaker profile by name","operationId":"get_speaker_profile_api_speaker_profiles__profile_name__get","parameters":[{"name":"profile_name","in":"path","required":true,"schema":{"type":"string","title":"Profile Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeakerProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/speaker-profiles/{profile_id}":{"put":{"tags":["speaker-profiles"],"summary":"Update Speaker Profile","description":"Update an existing speaker profile","operationId":"update_speaker_profile_api_speaker_profiles__profile_id__put","parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"string","title":"Profile Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeakerProfileCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeakerProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["speaker-profiles"],"summary":"Delete Speaker Profile","description":"Delete a speaker profile","operationId":"delete_speaker_profile_api_speaker_profiles__profile_id__delete","parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"string","title":"Profile Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/speaker-profiles/{profile_id}/duplicate":{"post":{"tags":["speaker-profiles"],"summary":"Duplicate Speaker Profile","description":"Duplicate a speaker profile","operationId":"duplicate_speaker_profile_api_speaker_profiles__profile_id__duplicate_post","parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"string","title":"Profile Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SpeakerProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/chat/sessions":{"get":{"tags":["chat"],"summary":"Get Sessions","description":"Get all chat sessions for a notebook.","operationId":"get_sessions_api_chat_sessions_get","parameters":[{"name":"notebook_id","in":"query","required":true,"schema":{"type":"string","description":"Notebook ID","title":"Notebook Id"},"description":"Notebook ID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ChatSessionResponse"},"title":"Response Get Sessions Api Chat Sessions Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["chat"],"summary":"Create Session","description":"Create a new chat session.","operationId":"create_session_api_chat_sessions_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSessionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatSessionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/chat/sessions/{session_id}":{"get":{"tags":["chat"],"summary":"Get Session","description":"Get a specific session with its messages.","operationId":"get_session_api_chat_sessions__session_id__get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatSessionWithMessagesResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["chat"],"summary":"Update Session","description":"Update session title.","operationId":"update_session_api_chat_sessions__session_id__put","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSessionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatSessionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["chat"],"summary":"Delete Session","description":"Delete a chat session.","operationId":"delete_session_api_chat_sessions__session_id__delete","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__routers__source_chat__SuccessResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/chat/execute":{"post":{"tags":["chat"],"summary":"Execute Chat","description":"Execute a chat request and get AI response.","operationId":"execute_chat_api_chat_execute_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteChatRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteChatResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/chat/context":{"post":{"tags":["chat"],"summary":"Build Context","description":"Build context for a notebook based on context configuration.","operationId":"build_context_api_chat_context_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BuildContextRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BuildContextResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sources/{source_id}/chat/sessions":{"post":{"tags":["source-chat"],"summary":"Create Source Chat Session","description":"Create a new chat session for a source.","operationId":"create_source_chat_session_api_sources__source_id__chat_sessions_post","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"string","description":"Source ID","title":"Source Id"},"description":"Source ID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSourceChatSessionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceChatSessionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["source-chat"],"summary":"Get Source Chat Sessions","description":"Get all chat sessions for a source.","operationId":"get_source_chat_sessions_api_sources__source_id__chat_sessions_get","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"string","description":"Source ID","title":"Source Id"},"description":"Source ID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SourceChatSessionResponse"},"title":"Response Get Source Chat Sessions Api Sources Source Id Chat Sessions Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sources/{source_id}/chat/sessions/{session_id}":{"get":{"tags":["source-chat"],"summary":"Get Source Chat Session","description":"Get a specific source chat session with its messages.","operationId":"get_source_chat_session_api_sources__source_id__chat_sessions__session_id__get","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"string","description":"Source ID","title":"Source Id"},"description":"Source ID"},{"name":"session_id","in":"path","required":true,"schema":{"type":"string","description":"Session ID","title":"Session Id"},"description":"Session ID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceChatSessionWithMessagesResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["source-chat"],"summary":"Update Source Chat Session","description":"Update source chat session title and/or model override.","operationId":"update_source_chat_session_api_sources__source_id__chat_sessions__session_id__put","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"string","description":"Source ID","title":"Source Id"},"description":"Source ID"},{"name":"session_id","in":"path","required":true,"schema":{"type":"string","description":"Session ID","title":"Session Id"},"description":"Session ID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSourceChatSessionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceChatSessionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["source-chat"],"summary":"Delete Source Chat Session","description":"Delete a source chat session.","operationId":"delete_source_chat_session_api_sources__source_id__chat_sessions__session_id__delete","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"string","description":"Source ID","title":"Source Id"},"description":"Source ID"},{"name":"session_id","in":"path","required":true,"schema":{"type":"string","description":"Session ID","title":"Session Id"},"description":"Session ID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/api__routers__source_chat__SuccessResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/sources/{source_id}/chat/sessions/{session_id}/messages":{"post":{"tags":["source-chat"],"summary":"Send Message To Source Chat","description":"Send a message to source chat session with SSE streaming response.","operationId":"send_message_to_source_chat_api_sources__source_id__chat_sessions__session_id__messages_post","parameters":[{"name":"source_id","in":"path","required":true,"schema":{"type":"string","description":"Source ID","title":"Source Id"},"description":"Source ID"},{"name":"session_id","in":"path","required":true,"schema":{"type":"string","description":"Session ID","title":"Session Id"},"description":"Session ID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/":{"get":{"summary":"Root","operationId":"root__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"summary":"Health","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AskRequest":{"properties":{"question":{"type":"string","title":"Question","description":"Question to ask the knowledge base"},"strategy_model":{"type":"string","title":"Strategy Model","description":"Model ID for query strategy"},"answer_model":{"type":"string","title":"Answer Model","description":"Model ID for individual answers"},"final_answer_model":{"type":"string","title":"Final Answer Model","description":"Model ID for final answer"}},"type":"object","required":["question","strategy_model","answer_model","final_answer_model"],"title":"AskRequest"},"AskResponse":{"properties":{"answer":{"type":"string","title":"Answer","description":"Final answer from the knowledge base"},"question":{"type":"string","title":"Question","description":"Original question"}},"type":"object","required":["answer","question"],"title":"AskResponse"},"AssetModel":{"properties":{"file_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Path"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"}},"type":"object","title":"AssetModel"},"Body_create_source_api_sources_post":{"properties":{"type":{"type":"string","title":"Type"},"notebook_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notebook Id"},"notebooks":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notebooks"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"transformations":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Transformations"},"embed":{"type":"string","title":"Embed","default":"false"},"delete_source":{"type":"string","title":"Delete Source","default":"false"},"async_processing":{"type":"string","title":"Async Processing","default":"false"},"file":{"anyOf":[{"type":"string","format":"binary"},{"type":"null"}],"title":"File"}},"type":"object","required":["type"],"title":"Body_create_source_api_sources_post"},"BuildContextRequest":{"properties":{"notebook_id":{"type":"string","title":"Notebook Id","description":"Notebook ID"},"context_config":{"additionalProperties":true,"type":"object","title":"Context Config","description":"Context configuration"}},"type":"object","required":["notebook_id","context_config"],"title":"BuildContextRequest"},"BuildContextResponse":{"properties":{"context":{"additionalProperties":true,"type":"object","title":"Context","description":"Built context data"},"token_count":{"type":"integer","title":"Token Count","description":"Estimated token count"},"char_count":{"type":"integer","title":"Char Count","description":"Character count"}},"type":"object","required":["context","token_count","char_count"],"title":"BuildContextResponse"},"ChatSessionResponse":{"properties":{"id":{"type":"string","title":"Id","description":"Session ID"},"title":{"type":"string","title":"Title","description":"Session title"},"notebook_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notebook Id","description":"Notebook ID"},"created":{"type":"string","title":"Created","description":"Creation timestamp"},"updated":{"type":"string","title":"Updated","description":"Last update timestamp"},"message_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Message Count","description":"Number of messages in session"},"model_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Override","description":"Model override for this session"}},"type":"object","required":["id","title","created","updated"],"title":"ChatSessionResponse"},"ChatSessionWithMessagesResponse":{"properties":{"id":{"type":"string","title":"Id","description":"Session ID"},"title":{"type":"string","title":"Title","description":"Session title"},"notebook_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notebook Id","description":"Notebook ID"},"created":{"type":"string","title":"Created","description":"Creation timestamp"},"updated":{"type":"string","title":"Updated","description":"Last update timestamp"},"message_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Message Count","description":"Number of messages in session"},"model_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Override","description":"Model override for this session"},"messages":{"items":{"$ref":"#/components/schemas/api__routers__chat__ChatMessage"},"type":"array","title":"Messages","description":"Session messages"}},"type":"object","required":["id","title","created","updated"],"title":"ChatSessionWithMessagesResponse"},"CommandExecutionRequest":{"properties":{"command":{"type":"string","title":"Command","description":"Command function name (e.g., 'process_text')"},"app":{"type":"string","title":"App","description":"Application name (e.g., 'open_notebook')"},"input":{"additionalProperties":true,"type":"object","title":"Input","description":"Arguments to pass to the command"}},"type":"object","required":["command","app","input"],"title":"CommandExecutionRequest"},"CommandJobResponse":{"properties":{"job_id":{"type":"string","title":"Job Id"},"status":{"type":"string","title":"Status"},"message":{"type":"string","title":"Message"}},"type":"object","required":["job_id","status","message"],"title":"CommandJobResponse"},"CommandJobStatusResponse":{"properties":{"job_id":{"type":"string","title":"Job Id"},"status":{"type":"string","title":"Status"},"result":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Result"},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"},"created":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created"},"updated":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated"},"progress":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Progress"}},"type":"object","required":["job_id","status"],"title":"CommandJobStatusResponse"},"ContextConfig":{"properties":{"sources":{"additionalProperties":{"type":"string"},"type":"object","title":"Sources","description":"Source inclusion config {source_id: level}"},"notes":{"additionalProperties":{"type":"string"},"type":"object","title":"Notes","description":"Note inclusion config {note_id: level}"}},"type":"object","title":"ContextConfig"},"ContextIndicator":{"properties":{"sources":{"items":{"type":"string"},"type":"array","title":"Sources","description":"Source IDs used in context"},"insights":{"items":{"type":"string"},"type":"array","title":"Insights","description":"Insight IDs used in context"},"notes":{"items":{"type":"string"},"type":"array","title":"Notes","description":"Note IDs used in context"}},"type":"object","title":"ContextIndicator"},"ContextRequest":{"properties":{"notebook_id":{"type":"string","title":"Notebook Id","description":"Notebook ID to get context for"},"context_config":{"anyOf":[{"$ref":"#/components/schemas/ContextConfig"},{"type":"null"}],"description":"Context configuration"}},"type":"object","required":["notebook_id"],"title":"ContextRequest"},"ContextResponse":{"properties":{"notebook_id":{"type":"string","title":"Notebook Id"},"sources":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Sources","description":"Source context data"},"notes":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Notes","description":"Note context data"},"total_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Tokens","description":"Estimated token count"}},"type":"object","required":["notebook_id","sources","notes"],"title":"ContextResponse"},"CreateSessionRequest":{"properties":{"notebook_id":{"type":"string","title":"Notebook Id","description":"Notebook ID to create session for"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"Optional session title"},"model_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Override","description":"Optional model override for this session"}},"type":"object","required":["notebook_id"],"title":"CreateSessionRequest"},"CreateSourceChatSessionRequest":{"properties":{"source_id":{"type":"string","title":"Source Id","description":"Source ID to create chat session for"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"Optional session title"},"model_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Override","description":"Optional model override for this session"}},"type":"object","required":["source_id"],"title":"CreateSourceChatSessionRequest"},"CreateSourceInsightRequest":{"properties":{"transformation_id":{"type":"string","title":"Transformation Id","description":"ID of transformation to apply"},"model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Id","description":"Model ID (uses default if not provided)"}},"type":"object","required":["transformation_id"],"title":"CreateSourceInsightRequest"},"DefaultModelsResponse":{"properties":{"default_chat_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Chat Model"},"default_transformation_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Transformation Model"},"large_context_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Large Context Model"},"default_text_to_speech_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Text To Speech Model"},"default_speech_to_text_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Speech To Text Model"},"default_embedding_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Embedding Model"},"default_tools_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Tools Model"}},"type":"object","title":"DefaultModelsResponse"},"DefaultPromptResponse":{"properties":{"transformation_instructions":{"type":"string","title":"Transformation Instructions","description":"Default transformation instructions"}},"type":"object","required":["transformation_instructions"],"title":"DefaultPromptResponse"},"DefaultPromptUpdate":{"properties":{"transformation_instructions":{"type":"string","title":"Transformation Instructions","description":"Default transformation instructions"}},"type":"object","required":["transformation_instructions"],"title":"DefaultPromptUpdate"},"EmbedRequest":{"properties":{"item_id":{"type":"string","title":"Item Id","description":"ID of the item to embed"},"item_type":{"type":"string","title":"Item Type","description":"Type of item (source, note)"},"async_processing":{"type":"boolean","title":"Async Processing","description":"Process asynchronously in background","default":false}},"type":"object","required":["item_id","item_type"],"title":"EmbedRequest"},"EmbedResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Whether embedding was successful"},"message":{"type":"string","title":"Message","description":"Result message"},"item_id":{"type":"string","title":"Item Id","description":"ID of the item that was embedded"},"item_type":{"type":"string","title":"Item Type","description":"Type of item that was embedded"},"command_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Command Id","description":"Command ID for async processing"}},"type":"object","required":["success","message","item_id","item_type"],"title":"EmbedResponse"},"EpisodeProfileCreate":{"properties":{"name":{"type":"string","title":"Name","description":"Unique profile name"},"description":{"type":"string","title":"Description","description":"Profile description","default":""},"speaker_config":{"type":"string","title":"Speaker Config","description":"Reference to speaker profile name"},"outline_provider":{"type":"string","title":"Outline Provider","description":"AI provider for outline generation"},"outline_model":{"type":"string","title":"Outline Model","description":"AI model for outline generation"},"transcript_provider":{"type":"string","title":"Transcript Provider","description":"AI provider for transcript generation"},"transcript_model":{"type":"string","title":"Transcript Model","description":"AI model for transcript generation"},"default_briefing":{"type":"string","title":"Default Briefing","description":"Default briefing template"},"num_segments":{"type":"integer","title":"Num Segments","description":"Number of podcast segments","default":5}},"type":"object","required":["name","speaker_config","outline_provider","outline_model","transcript_provider","transcript_model","default_briefing"],"title":"EpisodeProfileCreate"},"EpisodeProfileResponse":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"type":"string","title":"Description"},"speaker_config":{"type":"string","title":"Speaker Config"},"outline_provider":{"type":"string","title":"Outline Provider"},"outline_model":{"type":"string","title":"Outline Model"},"transcript_provider":{"type":"string","title":"Transcript Provider"},"transcript_model":{"type":"string","title":"Transcript Model"},"default_briefing":{"type":"string","title":"Default Briefing"},"num_segments":{"type":"integer","title":"Num Segments"}},"type":"object","required":["id","name","description","speaker_config","outline_provider","outline_model","transcript_provider","transcript_model","default_briefing","num_segments"],"title":"EpisodeProfileResponse"},"ExecuteChatRequest":{"properties":{"session_id":{"type":"string","title":"Session Id","description":"Chat session ID"},"message":{"type":"string","title":"Message","description":"User message content"},"context":{"additionalProperties":true,"type":"object","title":"Context","description":"Chat context with sources and notes"},"model_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Override","description":"Optional model override for this message"}},"type":"object","required":["session_id","message","context"],"title":"ExecuteChatRequest"},"ExecuteChatResponse":{"properties":{"session_id":{"type":"string","title":"Session Id","description":"Session ID"},"messages":{"items":{"$ref":"#/components/schemas/api__routers__chat__ChatMessage"},"type":"array","title":"Messages","description":"Updated message list"}},"type":"object","required":["session_id","messages"],"title":"ExecuteChatResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ModelCreate":{"properties":{"name":{"type":"string","title":"Name","description":"Model name (e.g., gpt-5-mini, claude, gemini)"},"provider":{"type":"string","title":"Provider","description":"Provider name (e.g., openai, anthropic, gemini)"},"type":{"type":"string","title":"Type","description":"Model type (language, embedding, text_to_speech, speech_to_text)"}},"type":"object","required":["name","provider","type"],"title":"ModelCreate"},"ModelResponse":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"provider":{"type":"string","title":"Provider"},"type":{"type":"string","title":"Type"},"created":{"type":"string","title":"Created"},"updated":{"type":"string","title":"Updated"}},"type":"object","required":["id","name","provider","type","created","updated"],"title":"ModelResponse"},"NoteCreate":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"Note title"},"content":{"type":"string","title":"Content","description":"Note content"},"note_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Note Type","description":"Type of note (human, ai)","default":"human"},"notebook_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notebook Id","description":"Notebook ID to add the note to"}},"type":"object","required":["content"],"title":"NoteCreate"},"NoteResponse":{"properties":{"id":{"type":"string","title":"Id"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"note_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Note Type"},"created":{"type":"string","title":"Created"},"updated":{"type":"string","title":"Updated"}},"type":"object","required":["id","title","content","note_type","created","updated"],"title":"NoteResponse"},"NoteUpdate":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"Note title"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content","description":"Note content"},"note_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Note Type","description":"Type of note (human, ai)"}},"type":"object","title":"NoteUpdate"},"NotebookCreate":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the notebook"},"description":{"type":"string","title":"Description","description":"Description of the notebook","default":""}},"type":"object","required":["name"],"title":"NotebookCreate"},"NotebookResponse":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"type":"string","title":"Description"},"archived":{"type":"boolean","title":"Archived"},"created":{"type":"string","title":"Created"},"updated":{"type":"string","title":"Updated"},"source_count":{"type":"integer","title":"Source Count"},"note_count":{"type":"integer","title":"Note Count"}},"type":"object","required":["id","name","description","archived","created","updated","source_count","note_count"],"title":"NotebookResponse"},"NotebookUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Name of the notebook"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Description of the notebook"},"archived":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Archived","description":"Whether the notebook is archived"}},"type":"object","title":"NotebookUpdate"},"PodcastEpisodeResponse":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"episode_profile":{"additionalProperties":true,"type":"object","title":"Episode Profile"},"speaker_profile":{"additionalProperties":true,"type":"object","title":"Speaker Profile"},"briefing":{"type":"string","title":"Briefing"},"audio_file":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Audio File"},"audio_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Audio Url"},"transcript":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Transcript"},"outline":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Outline"},"created":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created"},"job_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Job Status"}},"type":"object","required":["id","name","episode_profile","speaker_profile","briefing"],"title":"PodcastEpisodeResponse"},"PodcastGenerationRequest":{"properties":{"episode_profile":{"type":"string","title":"Episode Profile"},"speaker_profile":{"type":"string","title":"Speaker Profile"},"episode_name":{"type":"string","title":"Episode Name"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"notebook_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notebook Id"},"briefing_suffix":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Briefing Suffix"}},"type":"object","required":["episode_profile","speaker_profile","episode_name"],"title":"PodcastGenerationRequest","description":"Request model for podcast generation"},"PodcastGenerationResponse":{"properties":{"job_id":{"type":"string","title":"Job Id"},"status":{"type":"string","title":"Status"},"message":{"type":"string","title":"Message"},"episode_profile":{"type":"string","title":"Episode Profile"},"episode_name":{"type":"string","title":"Episode Name"}},"type":"object","required":["job_id","status","message","episode_profile","episode_name"],"title":"PodcastGenerationResponse","description":"Response model for podcast generation"},"ProviderAvailabilityResponse":{"properties":{"available":{"items":{"type":"string"},"type":"array","title":"Available","description":"List of available providers"},"unavailable":{"items":{"type":"string"},"type":"array","title":"Unavailable","description":"List of unavailable providers"},"supported_types":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object","title":"Supported Types","description":"Provider to supported model types mapping"}},"type":"object","required":["available","unavailable","supported_types"],"title":"ProviderAvailabilityResponse"},"RebuildProgress":{"properties":{"processed":{"type":"integer","title":"Processed","description":"Number of items processed"},"total":{"type":"integer","title":"Total","description":"Total items to process"},"percentage":{"type":"number","title":"Percentage","description":"Progress percentage"}},"type":"object","required":["processed","total","percentage"],"title":"RebuildProgress"},"RebuildRequest":{"properties":{"mode":{"type":"string","enum":["existing","all"],"title":"Mode","description":"Rebuild mode: 'existing' only re-embeds items with embeddings, 'all' embeds everything"},"include_sources":{"type":"boolean","title":"Include Sources","description":"Include sources in rebuild","default":true},"include_notes":{"type":"boolean","title":"Include Notes","description":"Include notes in rebuild","default":true},"include_insights":{"type":"boolean","title":"Include Insights","description":"Include insights in rebuild","default":true}},"type":"object","required":["mode"],"title":"RebuildRequest"},"RebuildResponse":{"properties":{"command_id":{"type":"string","title":"Command Id","description":"Command ID to track progress"},"total_items":{"type":"integer","title":"Total Items","description":"Estimated number of items to process"},"message":{"type":"string","title":"Message","description":"Status message"}},"type":"object","required":["command_id","total_items","message"],"title":"RebuildResponse"},"RebuildStats":{"properties":{"sources":{"type":"integer","title":"Sources","description":"Sources processed","default":0},"notes":{"type":"integer","title":"Notes","description":"Notes processed","default":0},"insights":{"type":"integer","title":"Insights","description":"Insights processed","default":0},"failed":{"type":"integer","title":"Failed","description":"Failed items","default":0}},"type":"object","title":"RebuildStats"},"RebuildStatusResponse":{"properties":{"command_id":{"type":"string","title":"Command Id","description":"Command ID"},"status":{"type":"string","title":"Status","description":"Status: queued, running, completed, failed"},"progress":{"anyOf":[{"$ref":"#/components/schemas/RebuildProgress"},{"type":"null"}]},"stats":{"anyOf":[{"$ref":"#/components/schemas/RebuildStats"},{"type":"null"}]},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started At"},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Completed At"},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"}},"type":"object","required":["command_id","status"],"title":"RebuildStatusResponse"},"SaveAsNoteRequest":{"properties":{"notebook_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notebook Id","description":"Notebook ID to add note to"}},"type":"object","title":"SaveAsNoteRequest"},"SearchRequest":{"properties":{"query":{"type":"string","title":"Query","description":"Search query"},"type":{"type":"string","enum":["text","vector"],"title":"Type","description":"Search type","default":"text"},"limit":{"type":"integer","maximum":1000.0,"title":"Limit","description":"Maximum number of results","default":100},"search_sources":{"type":"boolean","title":"Search Sources","description":"Include sources in search","default":true},"search_notes":{"type":"boolean","title":"Search Notes","description":"Include notes in search","default":true},"minimum_score":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Minimum Score","description":"Minimum score for vector search","default":0.2}},"type":"object","required":["query"],"title":"SearchRequest"},"SearchResponse":{"properties":{"results":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Results","description":"Search results"},"total_count":{"type":"integer","title":"Total Count","description":"Total number of results"},"search_type":{"type":"string","title":"Search Type","description":"Type of search performed"}},"type":"object","required":["results","total_count","search_type"],"title":"SearchResponse"},"SendMessageRequest":{"properties":{"message":{"type":"string","title":"Message","description":"User message content"},"model_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Override","description":"Optional model override for this message"}},"type":"object","required":["message"],"title":"SendMessageRequest"},"SettingsResponse":{"properties":{"default_content_processing_engine_doc":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Content Processing Engine Doc"},"default_content_processing_engine_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Content Processing Engine Url"},"default_embedding_option":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Embedding Option"},"auto_delete_files":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Auto Delete Files"},"youtube_preferred_languages":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Youtube Preferred Languages"}},"type":"object","title":"SettingsResponse"},"SettingsUpdate":{"properties":{"default_content_processing_engine_doc":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Content Processing Engine Doc"},"default_content_processing_engine_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Content Processing Engine Url"},"default_embedding_option":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Embedding Option"},"auto_delete_files":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Auto Delete Files"},"youtube_preferred_languages":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Youtube Preferred Languages"}},"type":"object","title":"SettingsUpdate"},"SourceChatSessionResponse":{"properties":{"id":{"type":"string","title":"Id","description":"Session ID"},"title":{"type":"string","title":"Title","description":"Session title"},"source_id":{"type":"string","title":"Source Id","description":"Source ID"},"model_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Override","description":"Model override for this session"},"created":{"type":"string","title":"Created","description":"Creation timestamp"},"updated":{"type":"string","title":"Updated","description":"Last update timestamp"},"message_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Message Count","description":"Number of messages in session"}},"type":"object","required":["id","title","source_id","created","updated"],"title":"SourceChatSessionResponse"},"SourceChatSessionWithMessagesResponse":{"properties":{"id":{"type":"string","title":"Id","description":"Session ID"},"title":{"type":"string","title":"Title","description":"Session title"},"source_id":{"type":"string","title":"Source Id","description":"Source ID"},"model_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Override","description":"Model override for this session"},"created":{"type":"string","title":"Created","description":"Creation timestamp"},"updated":{"type":"string","title":"Updated","description":"Last update timestamp"},"message_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Message Count","description":"Number of messages in session"},"messages":{"items":{"$ref":"#/components/schemas/api__routers__chat__ChatMessage"},"type":"array","title":"Messages","description":"Session messages"},"context_indicators":{"anyOf":[{"$ref":"#/components/schemas/ContextIndicator"},{"type":"null"}],"description":"Context indicators from last response"}},"type":"object","required":["id","title","source_id","created","updated"],"title":"SourceChatSessionWithMessagesResponse"},"SourceCreate":{"properties":{"notebook_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notebook Id","description":"Notebook ID to add the source to (deprecated, use notebooks)"},"notebooks":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Notebooks","description":"List of notebook IDs to add the source to"},"type":{"type":"string","title":"Type","description":"Source type: link, upload, or text"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url","description":"URL for link type"},"file_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Path","description":"File path for upload type"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content","description":"Text content for text type"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"Source title"},"transformations":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Transformations","description":"Transformation IDs to apply"},"embed":{"type":"boolean","title":"Embed","description":"Whether to embed content for vector search","default":false},"delete_source":{"type":"boolean","title":"Delete Source","description":"Whether to delete uploaded file after processing","default":false},"async_processing":{"type":"boolean","title":"Async Processing","description":"Whether to process source asynchronously","default":false}},"type":"object","required":["type"],"title":"SourceCreate"},"SourceInsightResponse":{"properties":{"id":{"type":"string","title":"Id"},"source_id":{"type":"string","title":"Source Id"},"insight_type":{"type":"string","title":"Insight Type"},"content":{"type":"string","title":"Content"},"created":{"type":"string","title":"Created"},"updated":{"type":"string","title":"Updated"}},"type":"object","required":["id","source_id","insight_type","content","created","updated"],"title":"SourceInsightResponse"},"SourceListResponse":{"properties":{"id":{"type":"string","title":"Id"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"topics":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Topics"},"asset":{"anyOf":[{"$ref":"#/components/schemas/AssetModel"},{"type":"null"}]},"embedded":{"type":"boolean","title":"Embedded"},"embedded_chunks":{"type":"integer","title":"Embedded Chunks"},"insights_count":{"type":"integer","title":"Insights Count"},"created":{"type":"string","title":"Created"},"updated":{"type":"string","title":"Updated"},"file_available":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"File Available"},"command_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Command Id"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"processing_info":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Processing Info"}},"type":"object","required":["id","title","topics","asset","embedded","embedded_chunks","insights_count","created","updated"],"title":"SourceListResponse"},"SourceResponse":{"properties":{"id":{"type":"string","title":"Id"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"topics":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Topics"},"asset":{"anyOf":[{"$ref":"#/components/schemas/AssetModel"},{"type":"null"}]},"full_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Full Text"},"embedded":{"type":"boolean","title":"Embedded"},"embedded_chunks":{"type":"integer","title":"Embedded Chunks"},"file_available":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"File Available"},"created":{"type":"string","title":"Created"},"updated":{"type":"string","title":"Updated"},"command_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Command Id"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"processing_info":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Processing Info"},"notebooks":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Notebooks"}},"type":"object","required":["id","title","topics","asset","full_text","embedded","embedded_chunks","created","updated"],"title":"SourceResponse"},"SourceStatusResponse":{"properties":{"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status","description":"Processing status"},"message":{"type":"string","title":"Message","description":"Descriptive message about the status"},"processing_info":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Processing Info","description":"Detailed processing information"},"command_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Command Id","description":"Command ID if available"}},"type":"object","required":["message"],"title":"SourceStatusResponse"},"SourceUpdate":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"Source title"},"topics":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Topics","description":"Source topics"}},"type":"object","title":"SourceUpdate"},"SpeakerProfileCreate":{"properties":{"name":{"type":"string","title":"Name","description":"Unique profile name"},"description":{"type":"string","title":"Description","description":"Profile description","default":""},"tts_provider":{"type":"string","title":"Tts Provider","description":"TTS provider"},"tts_model":{"type":"string","title":"Tts Model","description":"TTS model name"},"speakers":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Speakers","description":"Array of speaker configurations"}},"type":"object","required":["name","tts_provider","tts_model","speakers"],"title":"SpeakerProfileCreate"},"SpeakerProfileResponse":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"type":"string","title":"Description"},"tts_provider":{"type":"string","title":"Tts Provider"},"tts_model":{"type":"string","title":"Tts Model"},"speakers":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Speakers"}},"type":"object","required":["id","name","description","tts_provider","tts_model","speakers"],"title":"SpeakerProfileResponse"},"TransformationCreate":{"properties":{"name":{"type":"string","title":"Name","description":"Transformation name"},"title":{"type":"string","title":"Title","description":"Display title for the transformation"},"description":{"type":"string","title":"Description","description":"Description of what this transformation does"},"prompt":{"type":"string","title":"Prompt","description":"The transformation prompt"},"apply_default":{"type":"boolean","title":"Apply Default","description":"Whether to apply this transformation by default","default":false}},"type":"object","required":["name","title","description","prompt"],"title":"TransformationCreate"},"TransformationExecuteRequest":{"properties":{"transformation_id":{"type":"string","title":"Transformation Id","description":"ID of the transformation to execute"},"input_text":{"type":"string","title":"Input Text","description":"Text to transform"},"model_id":{"type":"string","title":"Model Id","description":"Model ID to use for the transformation"}},"type":"object","required":["transformation_id","input_text","model_id"],"title":"TransformationExecuteRequest"},"TransformationExecuteResponse":{"properties":{"output":{"type":"string","title":"Output","description":"Transformed text"},"transformation_id":{"type":"string","title":"Transformation Id","description":"ID of the transformation used"},"model_id":{"type":"string","title":"Model Id","description":"Model ID used"}},"type":"object","required":["output","transformation_id","model_id"],"title":"TransformationExecuteResponse"},"TransformationResponse":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"title":{"type":"string","title":"Title"},"description":{"type":"string","title":"Description"},"prompt":{"type":"string","title":"Prompt"},"apply_default":{"type":"boolean","title":"Apply Default"},"created":{"type":"string","title":"Created"},"updated":{"type":"string","title":"Updated"}},"type":"object","required":["id","name","title","description","prompt","apply_default","created","updated"],"title":"TransformationResponse"},"TransformationUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Transformation name"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"Display title for the transformation"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Description of what this transformation does"},"prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prompt","description":"The transformation prompt"},"apply_default":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Apply Default","description":"Whether to apply this transformation by default"}},"type":"object","title":"TransformationUpdate"},"UpdateSessionRequest":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"New session title"},"model_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Override","description":"Model override for this session"}},"type":"object","title":"UpdateSessionRequest"},"UpdateSourceChatSessionRequest":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"New session title"},"model_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Override","description":"Model override for this session"}},"type":"object","title":"UpdateSourceChatSessionRequest"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"api__routers__chat__ChatMessage":{"properties":{"id":{"type":"string","title":"Id","description":"Message ID"},"type":{"type":"string","title":"Type","description":"Message type (human|ai)"},"content":{"type":"string","title":"Content","description":"Message content"},"timestamp":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Timestamp","description":"Message timestamp"}},"type":"object","required":["id","type","content"],"title":"ChatMessage"},"api__routers__source_chat__SuccessResponse":{"properties":{"success":{"type":"boolean","title":"Success","description":"Operation success status","default":true},"message":{"type":"string","title":"Message","description":"Success message"}},"type":"object","required":["message"],"title":"SuccessResponse"}}}}
openapi_pretty.json ADDED
The diff for this file is too large to render. See raw diff
 
package-lock.json ADDED
@@ -0,0 +1,2214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "3gpp-innovation-extractor",
3
+ "version": "0.0.0",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "3gpp-innovation-extractor",
9
+ "version": "0.0.0",
10
+ "dependencies": {
11
+ "dexie": "^4.2.1",
12
+ "dexie-react-hooks": "^4.2.0",
13
+ "lucide-react": "^0.555.0",
14
+ "react": "^19.2.0",
15
+ "react-dom": "^19.2.0",
16
+ "recharts": "^3.5.0"
17
+ },
18
+ "devDependencies": {
19
+ "@types/node": "^22.14.0",
20
+ "@vitejs/plugin-react": "^5.0.0",
21
+ "typescript": "~5.8.2",
22
+ "vite": "^6.2.0"
23
+ }
24
+ },
25
+ "node_modules/@babel/code-frame": {
26
+ "version": "7.27.1",
27
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
28
+ "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
29
+ "dev": true,
30
+ "license": "MIT",
31
+ "dependencies": {
32
+ "@babel/helper-validator-identifier": "^7.27.1",
33
+ "js-tokens": "^4.0.0",
34
+ "picocolors": "^1.1.1"
35
+ },
36
+ "engines": {
37
+ "node": ">=6.9.0"
38
+ }
39
+ },
40
+ "node_modules/@babel/compat-data": {
41
+ "version": "7.28.5",
42
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz",
43
+ "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==",
44
+ "dev": true,
45
+ "license": "MIT",
46
+ "engines": {
47
+ "node": ">=6.9.0"
48
+ }
49
+ },
50
+ "node_modules/@babel/core": {
51
+ "version": "7.28.5",
52
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
53
+ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
54
+ "dev": true,
55
+ "license": "MIT",
56
+ "dependencies": {
57
+ "@babel/code-frame": "^7.27.1",
58
+ "@babel/generator": "^7.28.5",
59
+ "@babel/helper-compilation-targets": "^7.27.2",
60
+ "@babel/helper-module-transforms": "^7.28.3",
61
+ "@babel/helpers": "^7.28.4",
62
+ "@babel/parser": "^7.28.5",
63
+ "@babel/template": "^7.27.2",
64
+ "@babel/traverse": "^7.28.5",
65
+ "@babel/types": "^7.28.5",
66
+ "@jridgewell/remapping": "^2.3.5",
67
+ "convert-source-map": "^2.0.0",
68
+ "debug": "^4.1.0",
69
+ "gensync": "^1.0.0-beta.2",
70
+ "json5": "^2.2.3",
71
+ "semver": "^6.3.1"
72
+ },
73
+ "engines": {
74
+ "node": ">=6.9.0"
75
+ },
76
+ "funding": {
77
+ "type": "opencollective",
78
+ "url": "https://opencollective.com/babel"
79
+ }
80
+ },
81
+ "node_modules/@babel/generator": {
82
+ "version": "7.28.5",
83
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz",
84
+ "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==",
85
+ "dev": true,
86
+ "license": "MIT",
87
+ "dependencies": {
88
+ "@babel/parser": "^7.28.5",
89
+ "@babel/types": "^7.28.5",
90
+ "@jridgewell/gen-mapping": "^0.3.12",
91
+ "@jridgewell/trace-mapping": "^0.3.28",
92
+ "jsesc": "^3.0.2"
93
+ },
94
+ "engines": {
95
+ "node": ">=6.9.0"
96
+ }
97
+ },
98
+ "node_modules/@babel/helper-compilation-targets": {
99
+ "version": "7.27.2",
100
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
101
+ "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==",
102
+ "dev": true,
103
+ "license": "MIT",
104
+ "dependencies": {
105
+ "@babel/compat-data": "^7.27.2",
106
+ "@babel/helper-validator-option": "^7.27.1",
107
+ "browserslist": "^4.24.0",
108
+ "lru-cache": "^5.1.1",
109
+ "semver": "^6.3.1"
110
+ },
111
+ "engines": {
112
+ "node": ">=6.9.0"
113
+ }
114
+ },
115
+ "node_modules/@babel/helper-globals": {
116
+ "version": "7.28.0",
117
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
118
+ "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
119
+ "dev": true,
120
+ "license": "MIT",
121
+ "engines": {
122
+ "node": ">=6.9.0"
123
+ }
124
+ },
125
+ "node_modules/@babel/helper-module-imports": {
126
+ "version": "7.27.1",
127
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
128
+ "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
129
+ "dev": true,
130
+ "license": "MIT",
131
+ "dependencies": {
132
+ "@babel/traverse": "^7.27.1",
133
+ "@babel/types": "^7.27.1"
134
+ },
135
+ "engines": {
136
+ "node": ">=6.9.0"
137
+ }
138
+ },
139
+ "node_modules/@babel/helper-module-transforms": {
140
+ "version": "7.28.3",
141
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz",
142
+ "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==",
143
+ "dev": true,
144
+ "license": "MIT",
145
+ "dependencies": {
146
+ "@babel/helper-module-imports": "^7.27.1",
147
+ "@babel/helper-validator-identifier": "^7.27.1",
148
+ "@babel/traverse": "^7.28.3"
149
+ },
150
+ "engines": {
151
+ "node": ">=6.9.0"
152
+ },
153
+ "peerDependencies": {
154
+ "@babel/core": "^7.0.0"
155
+ }
156
+ },
157
+ "node_modules/@babel/helper-plugin-utils": {
158
+ "version": "7.27.1",
159
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz",
160
+ "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==",
161
+ "dev": true,
162
+ "license": "MIT",
163
+ "engines": {
164
+ "node": ">=6.9.0"
165
+ }
166
+ },
167
+ "node_modules/@babel/helper-string-parser": {
168
+ "version": "7.27.1",
169
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
170
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
171
+ "dev": true,
172
+ "license": "MIT",
173
+ "engines": {
174
+ "node": ">=6.9.0"
175
+ }
176
+ },
177
+ "node_modules/@babel/helper-validator-identifier": {
178
+ "version": "7.28.5",
179
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
180
+ "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
181
+ "dev": true,
182
+ "license": "MIT",
183
+ "engines": {
184
+ "node": ">=6.9.0"
185
+ }
186
+ },
187
+ "node_modules/@babel/helper-validator-option": {
188
+ "version": "7.27.1",
189
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
190
+ "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
191
+ "dev": true,
192
+ "license": "MIT",
193
+ "engines": {
194
+ "node": ">=6.9.0"
195
+ }
196
+ },
197
+ "node_modules/@babel/helpers": {
198
+ "version": "7.28.4",
199
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz",
200
+ "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==",
201
+ "dev": true,
202
+ "license": "MIT",
203
+ "dependencies": {
204
+ "@babel/template": "^7.27.2",
205
+ "@babel/types": "^7.28.4"
206
+ },
207
+ "engines": {
208
+ "node": ">=6.9.0"
209
+ }
210
+ },
211
+ "node_modules/@babel/parser": {
212
+ "version": "7.28.5",
213
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz",
214
+ "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==",
215
+ "dev": true,
216
+ "license": "MIT",
217
+ "dependencies": {
218
+ "@babel/types": "^7.28.5"
219
+ },
220
+ "bin": {
221
+ "parser": "bin/babel-parser.js"
222
+ },
223
+ "engines": {
224
+ "node": ">=6.0.0"
225
+ }
226
+ },
227
+ "node_modules/@babel/plugin-transform-react-jsx-self": {
228
+ "version": "7.27.1",
229
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
230
+ "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
231
+ "dev": true,
232
+ "license": "MIT",
233
+ "dependencies": {
234
+ "@babel/helper-plugin-utils": "^7.27.1"
235
+ },
236
+ "engines": {
237
+ "node": ">=6.9.0"
238
+ },
239
+ "peerDependencies": {
240
+ "@babel/core": "^7.0.0-0"
241
+ }
242
+ },
243
+ "node_modules/@babel/plugin-transform-react-jsx-source": {
244
+ "version": "7.27.1",
245
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
246
+ "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
247
+ "dev": true,
248
+ "license": "MIT",
249
+ "dependencies": {
250
+ "@babel/helper-plugin-utils": "^7.27.1"
251
+ },
252
+ "engines": {
253
+ "node": ">=6.9.0"
254
+ },
255
+ "peerDependencies": {
256
+ "@babel/core": "^7.0.0-0"
257
+ }
258
+ },
259
+ "node_modules/@babel/template": {
260
+ "version": "7.27.2",
261
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
262
+ "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
263
+ "dev": true,
264
+ "license": "MIT",
265
+ "dependencies": {
266
+ "@babel/code-frame": "^7.27.1",
267
+ "@babel/parser": "^7.27.2",
268
+ "@babel/types": "^7.27.1"
269
+ },
270
+ "engines": {
271
+ "node": ">=6.9.0"
272
+ }
273
+ },
274
+ "node_modules/@babel/traverse": {
275
+ "version": "7.28.5",
276
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz",
277
+ "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==",
278
+ "dev": true,
279
+ "license": "MIT",
280
+ "dependencies": {
281
+ "@babel/code-frame": "^7.27.1",
282
+ "@babel/generator": "^7.28.5",
283
+ "@babel/helper-globals": "^7.28.0",
284
+ "@babel/parser": "^7.28.5",
285
+ "@babel/template": "^7.27.2",
286
+ "@babel/types": "^7.28.5",
287
+ "debug": "^4.3.1"
288
+ },
289
+ "engines": {
290
+ "node": ">=6.9.0"
291
+ }
292
+ },
293
+ "node_modules/@babel/types": {
294
+ "version": "7.28.5",
295
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz",
296
+ "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==",
297
+ "dev": true,
298
+ "license": "MIT",
299
+ "dependencies": {
300
+ "@babel/helper-string-parser": "^7.27.1",
301
+ "@babel/helper-validator-identifier": "^7.28.5"
302
+ },
303
+ "engines": {
304
+ "node": ">=6.9.0"
305
+ }
306
+ },
307
+ "node_modules/@esbuild/aix-ppc64": {
308
+ "version": "0.25.12",
309
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
310
+ "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
311
+ "cpu": [
312
+ "ppc64"
313
+ ],
314
+ "dev": true,
315
+ "license": "MIT",
316
+ "optional": true,
317
+ "os": [
318
+ "aix"
319
+ ],
320
+ "engines": {
321
+ "node": ">=18"
322
+ }
323
+ },
324
+ "node_modules/@esbuild/android-arm": {
325
+ "version": "0.25.12",
326
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
327
+ "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
328
+ "cpu": [
329
+ "arm"
330
+ ],
331
+ "dev": true,
332
+ "license": "MIT",
333
+ "optional": true,
334
+ "os": [
335
+ "android"
336
+ ],
337
+ "engines": {
338
+ "node": ">=18"
339
+ }
340
+ },
341
+ "node_modules/@esbuild/android-arm64": {
342
+ "version": "0.25.12",
343
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
344
+ "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
345
+ "cpu": [
346
+ "arm64"
347
+ ],
348
+ "dev": true,
349
+ "license": "MIT",
350
+ "optional": true,
351
+ "os": [
352
+ "android"
353
+ ],
354
+ "engines": {
355
+ "node": ">=18"
356
+ }
357
+ },
358
+ "node_modules/@esbuild/android-x64": {
359
+ "version": "0.25.12",
360
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
361
+ "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
362
+ "cpu": [
363
+ "x64"
364
+ ],
365
+ "dev": true,
366
+ "license": "MIT",
367
+ "optional": true,
368
+ "os": [
369
+ "android"
370
+ ],
371
+ "engines": {
372
+ "node": ">=18"
373
+ }
374
+ },
375
+ "node_modules/@esbuild/darwin-arm64": {
376
+ "version": "0.25.12",
377
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
378
+ "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
379
+ "cpu": [
380
+ "arm64"
381
+ ],
382
+ "dev": true,
383
+ "license": "MIT",
384
+ "optional": true,
385
+ "os": [
386
+ "darwin"
387
+ ],
388
+ "engines": {
389
+ "node": ">=18"
390
+ }
391
+ },
392
+ "node_modules/@esbuild/darwin-x64": {
393
+ "version": "0.25.12",
394
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
395
+ "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
396
+ "cpu": [
397
+ "x64"
398
+ ],
399
+ "dev": true,
400
+ "license": "MIT",
401
+ "optional": true,
402
+ "os": [
403
+ "darwin"
404
+ ],
405
+ "engines": {
406
+ "node": ">=18"
407
+ }
408
+ },
409
+ "node_modules/@esbuild/freebsd-arm64": {
410
+ "version": "0.25.12",
411
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
412
+ "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
413
+ "cpu": [
414
+ "arm64"
415
+ ],
416
+ "dev": true,
417
+ "license": "MIT",
418
+ "optional": true,
419
+ "os": [
420
+ "freebsd"
421
+ ],
422
+ "engines": {
423
+ "node": ">=18"
424
+ }
425
+ },
426
+ "node_modules/@esbuild/freebsd-x64": {
427
+ "version": "0.25.12",
428
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
429
+ "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
430
+ "cpu": [
431
+ "x64"
432
+ ],
433
+ "dev": true,
434
+ "license": "MIT",
435
+ "optional": true,
436
+ "os": [
437
+ "freebsd"
438
+ ],
439
+ "engines": {
440
+ "node": ">=18"
441
+ }
442
+ },
443
+ "node_modules/@esbuild/linux-arm": {
444
+ "version": "0.25.12",
445
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
446
+ "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
447
+ "cpu": [
448
+ "arm"
449
+ ],
450
+ "dev": true,
451
+ "license": "MIT",
452
+ "optional": true,
453
+ "os": [
454
+ "linux"
455
+ ],
456
+ "engines": {
457
+ "node": ">=18"
458
+ }
459
+ },
460
+ "node_modules/@esbuild/linux-arm64": {
461
+ "version": "0.25.12",
462
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
463
+ "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
464
+ "cpu": [
465
+ "arm64"
466
+ ],
467
+ "dev": true,
468
+ "license": "MIT",
469
+ "optional": true,
470
+ "os": [
471
+ "linux"
472
+ ],
473
+ "engines": {
474
+ "node": ">=18"
475
+ }
476
+ },
477
+ "node_modules/@esbuild/linux-ia32": {
478
+ "version": "0.25.12",
479
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
480
+ "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
481
+ "cpu": [
482
+ "ia32"
483
+ ],
484
+ "dev": true,
485
+ "license": "MIT",
486
+ "optional": true,
487
+ "os": [
488
+ "linux"
489
+ ],
490
+ "engines": {
491
+ "node": ">=18"
492
+ }
493
+ },
494
+ "node_modules/@esbuild/linux-loong64": {
495
+ "version": "0.25.12",
496
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
497
+ "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
498
+ "cpu": [
499
+ "loong64"
500
+ ],
501
+ "dev": true,
502
+ "license": "MIT",
503
+ "optional": true,
504
+ "os": [
505
+ "linux"
506
+ ],
507
+ "engines": {
508
+ "node": ">=18"
509
+ }
510
+ },
511
+ "node_modules/@esbuild/linux-mips64el": {
512
+ "version": "0.25.12",
513
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
514
+ "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
515
+ "cpu": [
516
+ "mips64el"
517
+ ],
518
+ "dev": true,
519
+ "license": "MIT",
520
+ "optional": true,
521
+ "os": [
522
+ "linux"
523
+ ],
524
+ "engines": {
525
+ "node": ">=18"
526
+ }
527
+ },
528
+ "node_modules/@esbuild/linux-ppc64": {
529
+ "version": "0.25.12",
530
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
531
+ "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
532
+ "cpu": [
533
+ "ppc64"
534
+ ],
535
+ "dev": true,
536
+ "license": "MIT",
537
+ "optional": true,
538
+ "os": [
539
+ "linux"
540
+ ],
541
+ "engines": {
542
+ "node": ">=18"
543
+ }
544
+ },
545
+ "node_modules/@esbuild/linux-riscv64": {
546
+ "version": "0.25.12",
547
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
548
+ "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
549
+ "cpu": [
550
+ "riscv64"
551
+ ],
552
+ "dev": true,
553
+ "license": "MIT",
554
+ "optional": true,
555
+ "os": [
556
+ "linux"
557
+ ],
558
+ "engines": {
559
+ "node": ">=18"
560
+ }
561
+ },
562
+ "node_modules/@esbuild/linux-s390x": {
563
+ "version": "0.25.12",
564
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
565
+ "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
566
+ "cpu": [
567
+ "s390x"
568
+ ],
569
+ "dev": true,
570
+ "license": "MIT",
571
+ "optional": true,
572
+ "os": [
573
+ "linux"
574
+ ],
575
+ "engines": {
576
+ "node": ">=18"
577
+ }
578
+ },
579
+ "node_modules/@esbuild/linux-x64": {
580
+ "version": "0.25.12",
581
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
582
+ "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
583
+ "cpu": [
584
+ "x64"
585
+ ],
586
+ "dev": true,
587
+ "license": "MIT",
588
+ "optional": true,
589
+ "os": [
590
+ "linux"
591
+ ],
592
+ "engines": {
593
+ "node": ">=18"
594
+ }
595
+ },
596
+ "node_modules/@esbuild/netbsd-arm64": {
597
+ "version": "0.25.12",
598
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
599
+ "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
600
+ "cpu": [
601
+ "arm64"
602
+ ],
603
+ "dev": true,
604
+ "license": "MIT",
605
+ "optional": true,
606
+ "os": [
607
+ "netbsd"
608
+ ],
609
+ "engines": {
610
+ "node": ">=18"
611
+ }
612
+ },
613
+ "node_modules/@esbuild/netbsd-x64": {
614
+ "version": "0.25.12",
615
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
616
+ "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
617
+ "cpu": [
618
+ "x64"
619
+ ],
620
+ "dev": true,
621
+ "license": "MIT",
622
+ "optional": true,
623
+ "os": [
624
+ "netbsd"
625
+ ],
626
+ "engines": {
627
+ "node": ">=18"
628
+ }
629
+ },
630
+ "node_modules/@esbuild/openbsd-arm64": {
631
+ "version": "0.25.12",
632
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
633
+ "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
634
+ "cpu": [
635
+ "arm64"
636
+ ],
637
+ "dev": true,
638
+ "license": "MIT",
639
+ "optional": true,
640
+ "os": [
641
+ "openbsd"
642
+ ],
643
+ "engines": {
644
+ "node": ">=18"
645
+ }
646
+ },
647
+ "node_modules/@esbuild/openbsd-x64": {
648
+ "version": "0.25.12",
649
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
650
+ "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
651
+ "cpu": [
652
+ "x64"
653
+ ],
654
+ "dev": true,
655
+ "license": "MIT",
656
+ "optional": true,
657
+ "os": [
658
+ "openbsd"
659
+ ],
660
+ "engines": {
661
+ "node": ">=18"
662
+ }
663
+ },
664
+ "node_modules/@esbuild/openharmony-arm64": {
665
+ "version": "0.25.12",
666
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
667
+ "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
668
+ "cpu": [
669
+ "arm64"
670
+ ],
671
+ "dev": true,
672
+ "license": "MIT",
673
+ "optional": true,
674
+ "os": [
675
+ "openharmony"
676
+ ],
677
+ "engines": {
678
+ "node": ">=18"
679
+ }
680
+ },
681
+ "node_modules/@esbuild/sunos-x64": {
682
+ "version": "0.25.12",
683
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
684
+ "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
685
+ "cpu": [
686
+ "x64"
687
+ ],
688
+ "dev": true,
689
+ "license": "MIT",
690
+ "optional": true,
691
+ "os": [
692
+ "sunos"
693
+ ],
694
+ "engines": {
695
+ "node": ">=18"
696
+ }
697
+ },
698
+ "node_modules/@esbuild/win32-arm64": {
699
+ "version": "0.25.12",
700
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
701
+ "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
702
+ "cpu": [
703
+ "arm64"
704
+ ],
705
+ "dev": true,
706
+ "license": "MIT",
707
+ "optional": true,
708
+ "os": [
709
+ "win32"
710
+ ],
711
+ "engines": {
712
+ "node": ">=18"
713
+ }
714
+ },
715
+ "node_modules/@esbuild/win32-ia32": {
716
+ "version": "0.25.12",
717
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
718
+ "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
719
+ "cpu": [
720
+ "ia32"
721
+ ],
722
+ "dev": true,
723
+ "license": "MIT",
724
+ "optional": true,
725
+ "os": [
726
+ "win32"
727
+ ],
728
+ "engines": {
729
+ "node": ">=18"
730
+ }
731
+ },
732
+ "node_modules/@esbuild/win32-x64": {
733
+ "version": "0.25.12",
734
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
735
+ "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
736
+ "cpu": [
737
+ "x64"
738
+ ],
739
+ "dev": true,
740
+ "license": "MIT",
741
+ "optional": true,
742
+ "os": [
743
+ "win32"
744
+ ],
745
+ "engines": {
746
+ "node": ">=18"
747
+ }
748
+ },
749
+ "node_modules/@jridgewell/gen-mapping": {
750
+ "version": "0.3.13",
751
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
752
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
753
+ "dev": true,
754
+ "license": "MIT",
755
+ "dependencies": {
756
+ "@jridgewell/sourcemap-codec": "^1.5.0",
757
+ "@jridgewell/trace-mapping": "^0.3.24"
758
+ }
759
+ },
760
+ "node_modules/@jridgewell/remapping": {
761
+ "version": "2.3.5",
762
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
763
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
764
+ "dev": true,
765
+ "license": "MIT",
766
+ "dependencies": {
767
+ "@jridgewell/gen-mapping": "^0.3.5",
768
+ "@jridgewell/trace-mapping": "^0.3.24"
769
+ }
770
+ },
771
+ "node_modules/@jridgewell/resolve-uri": {
772
+ "version": "3.1.2",
773
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
774
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
775
+ "dev": true,
776
+ "license": "MIT",
777
+ "engines": {
778
+ "node": ">=6.0.0"
779
+ }
780
+ },
781
+ "node_modules/@jridgewell/sourcemap-codec": {
782
+ "version": "1.5.5",
783
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
784
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
785
+ "dev": true,
786
+ "license": "MIT"
787
+ },
788
+ "node_modules/@jridgewell/trace-mapping": {
789
+ "version": "0.3.31",
790
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
791
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
792
+ "dev": true,
793
+ "license": "MIT",
794
+ "dependencies": {
795
+ "@jridgewell/resolve-uri": "^3.1.0",
796
+ "@jridgewell/sourcemap-codec": "^1.4.14"
797
+ }
798
+ },
799
+ "node_modules/@reduxjs/toolkit": {
800
+ "version": "2.11.0",
801
+ "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.11.0.tgz",
802
+ "integrity": "sha512-hBjYg0aaRL1O2Z0IqWhnTLytnjDIxekmRxm1snsHjHaKVmIF1HiImWqsq+PuEbn6zdMlkIj9WofK1vR8jjx+Xw==",
803
+ "license": "MIT",
804
+ "dependencies": {
805
+ "@standard-schema/spec": "^1.0.0",
806
+ "@standard-schema/utils": "^0.3.0",
807
+ "immer": "^11.0.0",
808
+ "redux": "^5.0.1",
809
+ "redux-thunk": "^3.1.0",
810
+ "reselect": "^5.1.0"
811
+ },
812
+ "peerDependencies": {
813
+ "react": "^16.9.0 || ^17.0.0 || ^18 || ^19",
814
+ "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
815
+ },
816
+ "peerDependenciesMeta": {
817
+ "react": {
818
+ "optional": true
819
+ },
820
+ "react-redux": {
821
+ "optional": true
822
+ }
823
+ }
824
+ },
825
+ "node_modules/@reduxjs/toolkit/node_modules/immer": {
826
+ "version": "11.0.1",
827
+ "resolved": "https://registry.npmjs.org/immer/-/immer-11.0.1.tgz",
828
+ "integrity": "sha512-naDCyggtcBWANtIrjQEajhhBEuL9b0Zg4zmlWK2CzS6xCWSE39/vvf4LqnMjUAWHBhot4m9MHCM/Z+mfWhUkiA==",
829
+ "license": "MIT",
830
+ "funding": {
831
+ "type": "opencollective",
832
+ "url": "https://opencollective.com/immer"
833
+ }
834
+ },
835
+ "node_modules/@rolldown/pluginutils": {
836
+ "version": "1.0.0-beta.47",
837
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.47.tgz",
838
+ "integrity": "sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==",
839
+ "dev": true,
840
+ "license": "MIT"
841
+ },
842
+ "node_modules/@rollup/rollup-android-arm-eabi": {
843
+ "version": "4.53.3",
844
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz",
845
+ "integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==",
846
+ "cpu": [
847
+ "arm"
848
+ ],
849
+ "dev": true,
850
+ "license": "MIT",
851
+ "optional": true,
852
+ "os": [
853
+ "android"
854
+ ]
855
+ },
856
+ "node_modules/@rollup/rollup-android-arm64": {
857
+ "version": "4.53.3",
858
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz",
859
+ "integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==",
860
+ "cpu": [
861
+ "arm64"
862
+ ],
863
+ "dev": true,
864
+ "license": "MIT",
865
+ "optional": true,
866
+ "os": [
867
+ "android"
868
+ ]
869
+ },
870
+ "node_modules/@rollup/rollup-darwin-arm64": {
871
+ "version": "4.53.3",
872
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz",
873
+ "integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==",
874
+ "cpu": [
875
+ "arm64"
876
+ ],
877
+ "dev": true,
878
+ "license": "MIT",
879
+ "optional": true,
880
+ "os": [
881
+ "darwin"
882
+ ]
883
+ },
884
+ "node_modules/@rollup/rollup-darwin-x64": {
885
+ "version": "4.53.3",
886
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz",
887
+ "integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==",
888
+ "cpu": [
889
+ "x64"
890
+ ],
891
+ "dev": true,
892
+ "license": "MIT",
893
+ "optional": true,
894
+ "os": [
895
+ "darwin"
896
+ ]
897
+ },
898
+ "node_modules/@rollup/rollup-freebsd-arm64": {
899
+ "version": "4.53.3",
900
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz",
901
+ "integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==",
902
+ "cpu": [
903
+ "arm64"
904
+ ],
905
+ "dev": true,
906
+ "license": "MIT",
907
+ "optional": true,
908
+ "os": [
909
+ "freebsd"
910
+ ]
911
+ },
912
+ "node_modules/@rollup/rollup-freebsd-x64": {
913
+ "version": "4.53.3",
914
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz",
915
+ "integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==",
916
+ "cpu": [
917
+ "x64"
918
+ ],
919
+ "dev": true,
920
+ "license": "MIT",
921
+ "optional": true,
922
+ "os": [
923
+ "freebsd"
924
+ ]
925
+ },
926
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
927
+ "version": "4.53.3",
928
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz",
929
+ "integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==",
930
+ "cpu": [
931
+ "arm"
932
+ ],
933
+ "dev": true,
934
+ "license": "MIT",
935
+ "optional": true,
936
+ "os": [
937
+ "linux"
938
+ ]
939
+ },
940
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
941
+ "version": "4.53.3",
942
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz",
943
+ "integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==",
944
+ "cpu": [
945
+ "arm"
946
+ ],
947
+ "dev": true,
948
+ "license": "MIT",
949
+ "optional": true,
950
+ "os": [
951
+ "linux"
952
+ ]
953
+ },
954
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
955
+ "version": "4.53.3",
956
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz",
957
+ "integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==",
958
+ "cpu": [
959
+ "arm64"
960
+ ],
961
+ "dev": true,
962
+ "license": "MIT",
963
+ "optional": true,
964
+ "os": [
965
+ "linux"
966
+ ]
967
+ },
968
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
969
+ "version": "4.53.3",
970
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz",
971
+ "integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==",
972
+ "cpu": [
973
+ "arm64"
974
+ ],
975
+ "dev": true,
976
+ "license": "MIT",
977
+ "optional": true,
978
+ "os": [
979
+ "linux"
980
+ ]
981
+ },
982
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
983
+ "version": "4.53.3",
984
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz",
985
+ "integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==",
986
+ "cpu": [
987
+ "loong64"
988
+ ],
989
+ "dev": true,
990
+ "license": "MIT",
991
+ "optional": true,
992
+ "os": [
993
+ "linux"
994
+ ]
995
+ },
996
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
997
+ "version": "4.53.3",
998
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz",
999
+ "integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==",
1000
+ "cpu": [
1001
+ "ppc64"
1002
+ ],
1003
+ "dev": true,
1004
+ "license": "MIT",
1005
+ "optional": true,
1006
+ "os": [
1007
+ "linux"
1008
+ ]
1009
+ },
1010
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
1011
+ "version": "4.53.3",
1012
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz",
1013
+ "integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==",
1014
+ "cpu": [
1015
+ "riscv64"
1016
+ ],
1017
+ "dev": true,
1018
+ "license": "MIT",
1019
+ "optional": true,
1020
+ "os": [
1021
+ "linux"
1022
+ ]
1023
+ },
1024
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
1025
+ "version": "4.53.3",
1026
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz",
1027
+ "integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==",
1028
+ "cpu": [
1029
+ "riscv64"
1030
+ ],
1031
+ "dev": true,
1032
+ "license": "MIT",
1033
+ "optional": true,
1034
+ "os": [
1035
+ "linux"
1036
+ ]
1037
+ },
1038
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
1039
+ "version": "4.53.3",
1040
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz",
1041
+ "integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==",
1042
+ "cpu": [
1043
+ "s390x"
1044
+ ],
1045
+ "dev": true,
1046
+ "license": "MIT",
1047
+ "optional": true,
1048
+ "os": [
1049
+ "linux"
1050
+ ]
1051
+ },
1052
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
1053
+ "version": "4.53.3",
1054
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz",
1055
+ "integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==",
1056
+ "cpu": [
1057
+ "x64"
1058
+ ],
1059
+ "dev": true,
1060
+ "license": "MIT",
1061
+ "optional": true,
1062
+ "os": [
1063
+ "linux"
1064
+ ]
1065
+ },
1066
+ "node_modules/@rollup/rollup-linux-x64-musl": {
1067
+ "version": "4.53.3",
1068
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz",
1069
+ "integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==",
1070
+ "cpu": [
1071
+ "x64"
1072
+ ],
1073
+ "dev": true,
1074
+ "license": "MIT",
1075
+ "optional": true,
1076
+ "os": [
1077
+ "linux"
1078
+ ]
1079
+ },
1080
+ "node_modules/@rollup/rollup-openharmony-arm64": {
1081
+ "version": "4.53.3",
1082
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz",
1083
+ "integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==",
1084
+ "cpu": [
1085
+ "arm64"
1086
+ ],
1087
+ "dev": true,
1088
+ "license": "MIT",
1089
+ "optional": true,
1090
+ "os": [
1091
+ "openharmony"
1092
+ ]
1093
+ },
1094
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
1095
+ "version": "4.53.3",
1096
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz",
1097
+ "integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==",
1098
+ "cpu": [
1099
+ "arm64"
1100
+ ],
1101
+ "dev": true,
1102
+ "license": "MIT",
1103
+ "optional": true,
1104
+ "os": [
1105
+ "win32"
1106
+ ]
1107
+ },
1108
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
1109
+ "version": "4.53.3",
1110
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz",
1111
+ "integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==",
1112
+ "cpu": [
1113
+ "ia32"
1114
+ ],
1115
+ "dev": true,
1116
+ "license": "MIT",
1117
+ "optional": true,
1118
+ "os": [
1119
+ "win32"
1120
+ ]
1121
+ },
1122
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
1123
+ "version": "4.53.3",
1124
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz",
1125
+ "integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==",
1126
+ "cpu": [
1127
+ "x64"
1128
+ ],
1129
+ "dev": true,
1130
+ "license": "MIT",
1131
+ "optional": true,
1132
+ "os": [
1133
+ "win32"
1134
+ ]
1135
+ },
1136
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
1137
+ "version": "4.53.3",
1138
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz",
1139
+ "integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==",
1140
+ "cpu": [
1141
+ "x64"
1142
+ ],
1143
+ "dev": true,
1144
+ "license": "MIT",
1145
+ "optional": true,
1146
+ "os": [
1147
+ "win32"
1148
+ ]
1149
+ },
1150
+ "node_modules/@standard-schema/spec": {
1151
+ "version": "1.0.0",
1152
+ "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
1153
+ "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
1154
+ "license": "MIT"
1155
+ },
1156
+ "node_modules/@standard-schema/utils": {
1157
+ "version": "0.3.0",
1158
+ "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz",
1159
+ "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==",
1160
+ "license": "MIT"
1161
+ },
1162
+ "node_modules/@types/babel__core": {
1163
+ "version": "7.20.5",
1164
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
1165
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
1166
+ "dev": true,
1167
+ "license": "MIT",
1168
+ "dependencies": {
1169
+ "@babel/parser": "^7.20.7",
1170
+ "@babel/types": "^7.20.7",
1171
+ "@types/babel__generator": "*",
1172
+ "@types/babel__template": "*",
1173
+ "@types/babel__traverse": "*"
1174
+ }
1175
+ },
1176
+ "node_modules/@types/babel__generator": {
1177
+ "version": "7.27.0",
1178
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
1179
+ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
1180
+ "dev": true,
1181
+ "license": "MIT",
1182
+ "dependencies": {
1183
+ "@babel/types": "^7.0.0"
1184
+ }
1185
+ },
1186
+ "node_modules/@types/babel__template": {
1187
+ "version": "7.4.4",
1188
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
1189
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
1190
+ "dev": true,
1191
+ "license": "MIT",
1192
+ "dependencies": {
1193
+ "@babel/parser": "^7.1.0",
1194
+ "@babel/types": "^7.0.0"
1195
+ }
1196
+ },
1197
+ "node_modules/@types/babel__traverse": {
1198
+ "version": "7.28.0",
1199
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
1200
+ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
1201
+ "dev": true,
1202
+ "license": "MIT",
1203
+ "dependencies": {
1204
+ "@babel/types": "^7.28.2"
1205
+ }
1206
+ },
1207
+ "node_modules/@types/d3-array": {
1208
+ "version": "3.2.2",
1209
+ "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz",
1210
+ "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==",
1211
+ "license": "MIT"
1212
+ },
1213
+ "node_modules/@types/d3-color": {
1214
+ "version": "3.1.3",
1215
+ "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz",
1216
+ "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==",
1217
+ "license": "MIT"
1218
+ },
1219
+ "node_modules/@types/d3-ease": {
1220
+ "version": "3.0.2",
1221
+ "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz",
1222
+ "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==",
1223
+ "license": "MIT"
1224
+ },
1225
+ "node_modules/@types/d3-interpolate": {
1226
+ "version": "3.0.4",
1227
+ "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz",
1228
+ "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==",
1229
+ "license": "MIT",
1230
+ "dependencies": {
1231
+ "@types/d3-color": "*"
1232
+ }
1233
+ },
1234
+ "node_modules/@types/d3-path": {
1235
+ "version": "3.1.1",
1236
+ "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz",
1237
+ "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==",
1238
+ "license": "MIT"
1239
+ },
1240
+ "node_modules/@types/d3-scale": {
1241
+ "version": "4.0.9",
1242
+ "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz",
1243
+ "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==",
1244
+ "license": "MIT",
1245
+ "dependencies": {
1246
+ "@types/d3-time": "*"
1247
+ }
1248
+ },
1249
+ "node_modules/@types/d3-shape": {
1250
+ "version": "3.1.7",
1251
+ "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz",
1252
+ "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==",
1253
+ "license": "MIT",
1254
+ "dependencies": {
1255
+ "@types/d3-path": "*"
1256
+ }
1257
+ },
1258
+ "node_modules/@types/d3-time": {
1259
+ "version": "3.0.4",
1260
+ "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz",
1261
+ "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==",
1262
+ "license": "MIT"
1263
+ },
1264
+ "node_modules/@types/d3-timer": {
1265
+ "version": "3.0.2",
1266
+ "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz",
1267
+ "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==",
1268
+ "license": "MIT"
1269
+ },
1270
+ "node_modules/@types/estree": {
1271
+ "version": "1.0.8",
1272
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
1273
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
1274
+ "dev": true,
1275
+ "license": "MIT"
1276
+ },
1277
+ "node_modules/@types/node": {
1278
+ "version": "22.19.1",
1279
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.1.tgz",
1280
+ "integrity": "sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==",
1281
+ "dev": true,
1282
+ "license": "MIT",
1283
+ "dependencies": {
1284
+ "undici-types": "~6.21.0"
1285
+ }
1286
+ },
1287
+ "node_modules/@types/react": {
1288
+ "version": "19.2.7",
1289
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
1290
+ "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
1291
+ "license": "MIT",
1292
+ "peer": true,
1293
+ "dependencies": {
1294
+ "csstype": "^3.2.2"
1295
+ }
1296
+ },
1297
+ "node_modules/@types/use-sync-external-store": {
1298
+ "version": "0.0.6",
1299
+ "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
1300
+ "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
1301
+ "license": "MIT"
1302
+ },
1303
+ "node_modules/@vitejs/plugin-react": {
1304
+ "version": "5.1.1",
1305
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.1.tgz",
1306
+ "integrity": "sha512-WQfkSw0QbQ5aJ2CHYw23ZGkqnRwqKHD/KYsMeTkZzPT4Jcf0DcBxBtwMJxnu6E7oxw5+JC6ZAiePgh28uJ1HBA==",
1307
+ "dev": true,
1308
+ "license": "MIT",
1309
+ "dependencies": {
1310
+ "@babel/core": "^7.28.5",
1311
+ "@babel/plugin-transform-react-jsx-self": "^7.27.1",
1312
+ "@babel/plugin-transform-react-jsx-source": "^7.27.1",
1313
+ "@rolldown/pluginutils": "1.0.0-beta.47",
1314
+ "@types/babel__core": "^7.20.5",
1315
+ "react-refresh": "^0.18.0"
1316
+ },
1317
+ "engines": {
1318
+ "node": "^20.19.0 || >=22.12.0"
1319
+ },
1320
+ "peerDependencies": {
1321
+ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
1322
+ }
1323
+ },
1324
+ "node_modules/baseline-browser-mapping": {
1325
+ "version": "2.8.32",
1326
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.32.tgz",
1327
+ "integrity": "sha512-OPz5aBThlyLFgxyhdwf/s2+8ab3OvT7AdTNvKHBwpXomIYeXqpUUuT8LrdtxZSsWJ4R4CU1un4XGh5Ez3nlTpw==",
1328
+ "dev": true,
1329
+ "license": "Apache-2.0",
1330
+ "bin": {
1331
+ "baseline-browser-mapping": "dist/cli.js"
1332
+ }
1333
+ },
1334
+ "node_modules/browserslist": {
1335
+ "version": "4.28.0",
1336
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz",
1337
+ "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==",
1338
+ "dev": true,
1339
+ "funding": [
1340
+ {
1341
+ "type": "opencollective",
1342
+ "url": "https://opencollective.com/browserslist"
1343
+ },
1344
+ {
1345
+ "type": "tidelift",
1346
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
1347
+ },
1348
+ {
1349
+ "type": "github",
1350
+ "url": "https://github.com/sponsors/ai"
1351
+ }
1352
+ ],
1353
+ "license": "MIT",
1354
+ "dependencies": {
1355
+ "baseline-browser-mapping": "^2.8.25",
1356
+ "caniuse-lite": "^1.0.30001754",
1357
+ "electron-to-chromium": "^1.5.249",
1358
+ "node-releases": "^2.0.27",
1359
+ "update-browserslist-db": "^1.1.4"
1360
+ },
1361
+ "bin": {
1362
+ "browserslist": "cli.js"
1363
+ },
1364
+ "engines": {
1365
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
1366
+ }
1367
+ },
1368
+ "node_modules/caniuse-lite": {
1369
+ "version": "1.0.30001757",
1370
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001757.tgz",
1371
+ "integrity": "sha512-r0nnL/I28Zi/yjk1el6ilj27tKcdjLsNqAOZr0yVjWPrSQyHgKI2INaEWw21bAQSv2LXRt1XuCS/GomNpWOxsQ==",
1372
+ "dev": true,
1373
+ "funding": [
1374
+ {
1375
+ "type": "opencollective",
1376
+ "url": "https://opencollective.com/browserslist"
1377
+ },
1378
+ {
1379
+ "type": "tidelift",
1380
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
1381
+ },
1382
+ {
1383
+ "type": "github",
1384
+ "url": "https://github.com/sponsors/ai"
1385
+ }
1386
+ ],
1387
+ "license": "CC-BY-4.0"
1388
+ },
1389
+ "node_modules/clsx": {
1390
+ "version": "2.1.1",
1391
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
1392
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
1393
+ "license": "MIT",
1394
+ "engines": {
1395
+ "node": ">=6"
1396
+ }
1397
+ },
1398
+ "node_modules/convert-source-map": {
1399
+ "version": "2.0.0",
1400
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
1401
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
1402
+ "dev": true,
1403
+ "license": "MIT"
1404
+ },
1405
+ "node_modules/csstype": {
1406
+ "version": "3.2.3",
1407
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
1408
+ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
1409
+ "license": "MIT",
1410
+ "peer": true
1411
+ },
1412
+ "node_modules/d3-array": {
1413
+ "version": "3.2.4",
1414
+ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
1415
+ "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
1416
+ "license": "ISC",
1417
+ "dependencies": {
1418
+ "internmap": "1 - 2"
1419
+ },
1420
+ "engines": {
1421
+ "node": ">=12"
1422
+ }
1423
+ },
1424
+ "node_modules/d3-color": {
1425
+ "version": "3.1.0",
1426
+ "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
1427
+ "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
1428
+ "license": "ISC",
1429
+ "engines": {
1430
+ "node": ">=12"
1431
+ }
1432
+ },
1433
+ "node_modules/d3-ease": {
1434
+ "version": "3.0.1",
1435
+ "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
1436
+ "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
1437
+ "license": "BSD-3-Clause",
1438
+ "engines": {
1439
+ "node": ">=12"
1440
+ }
1441
+ },
1442
+ "node_modules/d3-format": {
1443
+ "version": "3.1.0",
1444
+ "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
1445
+ "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
1446
+ "license": "ISC",
1447
+ "engines": {
1448
+ "node": ">=12"
1449
+ }
1450
+ },
1451
+ "node_modules/d3-interpolate": {
1452
+ "version": "3.0.1",
1453
+ "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
1454
+ "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
1455
+ "license": "ISC",
1456
+ "dependencies": {
1457
+ "d3-color": "1 - 3"
1458
+ },
1459
+ "engines": {
1460
+ "node": ">=12"
1461
+ }
1462
+ },
1463
+ "node_modules/d3-path": {
1464
+ "version": "3.1.0",
1465
+ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
1466
+ "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
1467
+ "license": "ISC",
1468
+ "engines": {
1469
+ "node": ">=12"
1470
+ }
1471
+ },
1472
+ "node_modules/d3-scale": {
1473
+ "version": "4.0.2",
1474
+ "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
1475
+ "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
1476
+ "license": "ISC",
1477
+ "dependencies": {
1478
+ "d3-array": "2.10.0 - 3",
1479
+ "d3-format": "1 - 3",
1480
+ "d3-interpolate": "1.2.0 - 3",
1481
+ "d3-time": "2.1.1 - 3",
1482
+ "d3-time-format": "2 - 4"
1483
+ },
1484
+ "engines": {
1485
+ "node": ">=12"
1486
+ }
1487
+ },
1488
+ "node_modules/d3-shape": {
1489
+ "version": "3.2.0",
1490
+ "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
1491
+ "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
1492
+ "license": "ISC",
1493
+ "dependencies": {
1494
+ "d3-path": "^3.1.0"
1495
+ },
1496
+ "engines": {
1497
+ "node": ">=12"
1498
+ }
1499
+ },
1500
+ "node_modules/d3-time": {
1501
+ "version": "3.1.0",
1502
+ "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
1503
+ "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
1504
+ "license": "ISC",
1505
+ "dependencies": {
1506
+ "d3-array": "2 - 3"
1507
+ },
1508
+ "engines": {
1509
+ "node": ">=12"
1510
+ }
1511
+ },
1512
+ "node_modules/d3-time-format": {
1513
+ "version": "4.1.0",
1514
+ "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
1515
+ "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
1516
+ "license": "ISC",
1517
+ "dependencies": {
1518
+ "d3-time": "1 - 3"
1519
+ },
1520
+ "engines": {
1521
+ "node": ">=12"
1522
+ }
1523
+ },
1524
+ "node_modules/d3-timer": {
1525
+ "version": "3.0.1",
1526
+ "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
1527
+ "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
1528
+ "license": "ISC",
1529
+ "engines": {
1530
+ "node": ">=12"
1531
+ }
1532
+ },
1533
+ "node_modules/debug": {
1534
+ "version": "4.4.3",
1535
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
1536
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
1537
+ "dev": true,
1538
+ "license": "MIT",
1539
+ "dependencies": {
1540
+ "ms": "^2.1.3"
1541
+ },
1542
+ "engines": {
1543
+ "node": ">=6.0"
1544
+ },
1545
+ "peerDependenciesMeta": {
1546
+ "supports-color": {
1547
+ "optional": true
1548
+ }
1549
+ }
1550
+ },
1551
+ "node_modules/decimal.js-light": {
1552
+ "version": "2.5.1",
1553
+ "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz",
1554
+ "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==",
1555
+ "license": "MIT"
1556
+ },
1557
+ "node_modules/dexie": {
1558
+ "version": "4.2.1",
1559
+ "resolved": "https://registry.npmjs.org/dexie/-/dexie-4.2.1.tgz",
1560
+ "integrity": "sha512-Ckej0NS6jxQ4Po3OrSQBFddayRhTCic2DoCAG5zacOfOVB9P2Q5Xc5uL/nVa7ZVs+HdMnvUPzLFCB/JwpB6Csg==",
1561
+ "license": "Apache-2.0"
1562
+ },
1563
+ "node_modules/dexie-react-hooks": {
1564
+ "version": "4.2.0",
1565
+ "resolved": "https://registry.npmjs.org/dexie-react-hooks/-/dexie-react-hooks-4.2.0.tgz",
1566
+ "integrity": "sha512-u7KqTX9JpBQK8+tEyA9X0yMGXlSCsbm5AU64N6gjvGk/IutYDpLBInMYEAEC83s3qhIvryFS+W+sqLZUBEvePQ==",
1567
+ "license": "Apache-2.0",
1568
+ "peerDependencies": {
1569
+ "@types/react": ">=16",
1570
+ "dexie": ">=4.2.0-alpha.1 <5.0.0",
1571
+ "react": ">=16"
1572
+ }
1573
+ },
1574
+ "node_modules/electron-to-chromium": {
1575
+ "version": "1.5.262",
1576
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.262.tgz",
1577
+ "integrity": "sha512-NlAsMteRHek05jRUxUR0a5jpjYq9ykk6+kO0yRaMi5moe7u0fVIOeQ3Y30A8dIiWFBNUoQGi1ljb1i5VtS9WQQ==",
1578
+ "dev": true,
1579
+ "license": "ISC"
1580
+ },
1581
+ "node_modules/es-toolkit": {
1582
+ "version": "1.42.0",
1583
+ "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.42.0.tgz",
1584
+ "integrity": "sha512-SLHIyY7VfDJBM8clz4+T2oquwTQxEzu263AyhVK4jREOAwJ+8eebaa4wM3nlvnAqhDrMm2EsA6hWHaQsMPQ1nA==",
1585
+ "license": "MIT",
1586
+ "workspaces": [
1587
+ "docs",
1588
+ "benchmarks"
1589
+ ]
1590
+ },
1591
+ "node_modules/esbuild": {
1592
+ "version": "0.25.12",
1593
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
1594
+ "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
1595
+ "dev": true,
1596
+ "hasInstallScript": true,
1597
+ "license": "MIT",
1598
+ "bin": {
1599
+ "esbuild": "bin/esbuild"
1600
+ },
1601
+ "engines": {
1602
+ "node": ">=18"
1603
+ },
1604
+ "optionalDependencies": {
1605
+ "@esbuild/aix-ppc64": "0.25.12",
1606
+ "@esbuild/android-arm": "0.25.12",
1607
+ "@esbuild/android-arm64": "0.25.12",
1608
+ "@esbuild/android-x64": "0.25.12",
1609
+ "@esbuild/darwin-arm64": "0.25.12",
1610
+ "@esbuild/darwin-x64": "0.25.12",
1611
+ "@esbuild/freebsd-arm64": "0.25.12",
1612
+ "@esbuild/freebsd-x64": "0.25.12",
1613
+ "@esbuild/linux-arm": "0.25.12",
1614
+ "@esbuild/linux-arm64": "0.25.12",
1615
+ "@esbuild/linux-ia32": "0.25.12",
1616
+ "@esbuild/linux-loong64": "0.25.12",
1617
+ "@esbuild/linux-mips64el": "0.25.12",
1618
+ "@esbuild/linux-ppc64": "0.25.12",
1619
+ "@esbuild/linux-riscv64": "0.25.12",
1620
+ "@esbuild/linux-s390x": "0.25.12",
1621
+ "@esbuild/linux-x64": "0.25.12",
1622
+ "@esbuild/netbsd-arm64": "0.25.12",
1623
+ "@esbuild/netbsd-x64": "0.25.12",
1624
+ "@esbuild/openbsd-arm64": "0.25.12",
1625
+ "@esbuild/openbsd-x64": "0.25.12",
1626
+ "@esbuild/openharmony-arm64": "0.25.12",
1627
+ "@esbuild/sunos-x64": "0.25.12",
1628
+ "@esbuild/win32-arm64": "0.25.12",
1629
+ "@esbuild/win32-ia32": "0.25.12",
1630
+ "@esbuild/win32-x64": "0.25.12"
1631
+ }
1632
+ },
1633
+ "node_modules/escalade": {
1634
+ "version": "3.2.0",
1635
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
1636
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
1637
+ "dev": true,
1638
+ "license": "MIT",
1639
+ "engines": {
1640
+ "node": ">=6"
1641
+ }
1642
+ },
1643
+ "node_modules/eventemitter3": {
1644
+ "version": "5.0.1",
1645
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
1646
+ "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
1647
+ "license": "MIT"
1648
+ },
1649
+ "node_modules/fdir": {
1650
+ "version": "6.5.0",
1651
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
1652
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
1653
+ "dev": true,
1654
+ "license": "MIT",
1655
+ "engines": {
1656
+ "node": ">=12.0.0"
1657
+ },
1658
+ "peerDependencies": {
1659
+ "picomatch": "^3 || ^4"
1660
+ },
1661
+ "peerDependenciesMeta": {
1662
+ "picomatch": {
1663
+ "optional": true
1664
+ }
1665
+ }
1666
+ },
1667
+ "node_modules/fsevents": {
1668
+ "version": "2.3.3",
1669
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
1670
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
1671
+ "dev": true,
1672
+ "hasInstallScript": true,
1673
+ "license": "MIT",
1674
+ "optional": true,
1675
+ "os": [
1676
+ "darwin"
1677
+ ],
1678
+ "engines": {
1679
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
1680
+ }
1681
+ },
1682
+ "node_modules/gensync": {
1683
+ "version": "1.0.0-beta.2",
1684
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
1685
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
1686
+ "dev": true,
1687
+ "license": "MIT",
1688
+ "engines": {
1689
+ "node": ">=6.9.0"
1690
+ }
1691
+ },
1692
+ "node_modules/immer": {
1693
+ "version": "10.2.0",
1694
+ "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz",
1695
+ "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==",
1696
+ "license": "MIT",
1697
+ "funding": {
1698
+ "type": "opencollective",
1699
+ "url": "https://opencollective.com/immer"
1700
+ }
1701
+ },
1702
+ "node_modules/internmap": {
1703
+ "version": "2.0.3",
1704
+ "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
1705
+ "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
1706
+ "license": "ISC",
1707
+ "engines": {
1708
+ "node": ">=12"
1709
+ }
1710
+ },
1711
+ "node_modules/js-tokens": {
1712
+ "version": "4.0.0",
1713
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
1714
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
1715
+ "dev": true,
1716
+ "license": "MIT"
1717
+ },
1718
+ "node_modules/jsesc": {
1719
+ "version": "3.1.0",
1720
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
1721
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
1722
+ "dev": true,
1723
+ "license": "MIT",
1724
+ "bin": {
1725
+ "jsesc": "bin/jsesc"
1726
+ },
1727
+ "engines": {
1728
+ "node": ">=6"
1729
+ }
1730
+ },
1731
+ "node_modules/json5": {
1732
+ "version": "2.2.3",
1733
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
1734
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
1735
+ "dev": true,
1736
+ "license": "MIT",
1737
+ "bin": {
1738
+ "json5": "lib/cli.js"
1739
+ },
1740
+ "engines": {
1741
+ "node": ">=6"
1742
+ }
1743
+ },
1744
+ "node_modules/lru-cache": {
1745
+ "version": "5.1.1",
1746
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
1747
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
1748
+ "dev": true,
1749
+ "license": "ISC",
1750
+ "dependencies": {
1751
+ "yallist": "^3.0.2"
1752
+ }
1753
+ },
1754
+ "node_modules/lucide-react": {
1755
+ "version": "0.555.0",
1756
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.555.0.tgz",
1757
+ "integrity": "sha512-D8FvHUGbxWBRQM90NZeIyhAvkFfsh3u9ekrMvJ30Z6gnpBHS6HC6ldLg7tL45hwiIz/u66eKDtdA23gwwGsAHA==",
1758
+ "license": "ISC",
1759
+ "peerDependencies": {
1760
+ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
1761
+ }
1762
+ },
1763
+ "node_modules/ms": {
1764
+ "version": "2.1.3",
1765
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1766
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1767
+ "dev": true,
1768
+ "license": "MIT"
1769
+ },
1770
+ "node_modules/nanoid": {
1771
+ "version": "3.3.11",
1772
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
1773
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
1774
+ "dev": true,
1775
+ "funding": [
1776
+ {
1777
+ "type": "github",
1778
+ "url": "https://github.com/sponsors/ai"
1779
+ }
1780
+ ],
1781
+ "license": "MIT",
1782
+ "bin": {
1783
+ "nanoid": "bin/nanoid.cjs"
1784
+ },
1785
+ "engines": {
1786
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
1787
+ }
1788
+ },
1789
+ "node_modules/node-releases": {
1790
+ "version": "2.0.27",
1791
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
1792
+ "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==",
1793
+ "dev": true,
1794
+ "license": "MIT"
1795
+ },
1796
+ "node_modules/picocolors": {
1797
+ "version": "1.1.1",
1798
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
1799
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
1800
+ "dev": true,
1801
+ "license": "ISC"
1802
+ },
1803
+ "node_modules/picomatch": {
1804
+ "version": "4.0.3",
1805
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
1806
+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
1807
+ "dev": true,
1808
+ "license": "MIT",
1809
+ "engines": {
1810
+ "node": ">=12"
1811
+ },
1812
+ "funding": {
1813
+ "url": "https://github.com/sponsors/jonschlinkert"
1814
+ }
1815
+ },
1816
+ "node_modules/postcss": {
1817
+ "version": "8.5.6",
1818
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
1819
+ "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
1820
+ "dev": true,
1821
+ "funding": [
1822
+ {
1823
+ "type": "opencollective",
1824
+ "url": "https://opencollective.com/postcss/"
1825
+ },
1826
+ {
1827
+ "type": "tidelift",
1828
+ "url": "https://tidelift.com/funding/github/npm/postcss"
1829
+ },
1830
+ {
1831
+ "type": "github",
1832
+ "url": "https://github.com/sponsors/ai"
1833
+ }
1834
+ ],
1835
+ "license": "MIT",
1836
+ "dependencies": {
1837
+ "nanoid": "^3.3.11",
1838
+ "picocolors": "^1.1.1",
1839
+ "source-map-js": "^1.2.1"
1840
+ },
1841
+ "engines": {
1842
+ "node": "^10 || ^12 || >=14"
1843
+ }
1844
+ },
1845
+ "node_modules/react": {
1846
+ "version": "19.2.0",
1847
+ "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
1848
+ "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
1849
+ "license": "MIT",
1850
+ "engines": {
1851
+ "node": ">=0.10.0"
1852
+ }
1853
+ },
1854
+ "node_modules/react-dom": {
1855
+ "version": "19.2.0",
1856
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
1857
+ "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
1858
+ "license": "MIT",
1859
+ "dependencies": {
1860
+ "scheduler": "^0.27.0"
1861
+ },
1862
+ "peerDependencies": {
1863
+ "react": "^19.2.0"
1864
+ }
1865
+ },
1866
+ "node_modules/react-is": {
1867
+ "version": "19.2.0",
1868
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.0.tgz",
1869
+ "integrity": "sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==",
1870
+ "license": "MIT",
1871
+ "peer": true
1872
+ },
1873
+ "node_modules/react-redux": {
1874
+ "version": "9.2.0",
1875
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
1876
+ "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
1877
+ "license": "MIT",
1878
+ "dependencies": {
1879
+ "@types/use-sync-external-store": "^0.0.6",
1880
+ "use-sync-external-store": "^1.4.0"
1881
+ },
1882
+ "peerDependencies": {
1883
+ "@types/react": "^18.2.25 || ^19",
1884
+ "react": "^18.0 || ^19",
1885
+ "redux": "^5.0.0"
1886
+ },
1887
+ "peerDependenciesMeta": {
1888
+ "@types/react": {
1889
+ "optional": true
1890
+ },
1891
+ "redux": {
1892
+ "optional": true
1893
+ }
1894
+ }
1895
+ },
1896
+ "node_modules/react-refresh": {
1897
+ "version": "0.18.0",
1898
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz",
1899
+ "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==",
1900
+ "dev": true,
1901
+ "license": "MIT",
1902
+ "engines": {
1903
+ "node": ">=0.10.0"
1904
+ }
1905
+ },
1906
+ "node_modules/recharts": {
1907
+ "version": "3.5.1",
1908
+ "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.5.1.tgz",
1909
+ "integrity": "sha512-+v+HJojK7gnEgG6h+b2u7k8HH7FhyFUzAc4+cPrsjL4Otdgqr/ecXzAnHciqlzV1ko064eNcsdzrYOM78kankA==",
1910
+ "license": "MIT",
1911
+ "workspaces": [
1912
+ "www"
1913
+ ],
1914
+ "dependencies": {
1915
+ "@reduxjs/toolkit": "1.x.x || 2.x.x",
1916
+ "clsx": "^2.1.1",
1917
+ "decimal.js-light": "^2.5.1",
1918
+ "es-toolkit": "^1.39.3",
1919
+ "eventemitter3": "^5.0.1",
1920
+ "immer": "^10.1.1",
1921
+ "react-redux": "8.x.x || 9.x.x",
1922
+ "reselect": "5.1.1",
1923
+ "tiny-invariant": "^1.3.3",
1924
+ "use-sync-external-store": "^1.2.2",
1925
+ "victory-vendor": "^37.0.2"
1926
+ },
1927
+ "engines": {
1928
+ "node": ">=18"
1929
+ },
1930
+ "peerDependencies": {
1931
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
1932
+ "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
1933
+ "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
1934
+ }
1935
+ },
1936
+ "node_modules/redux": {
1937
+ "version": "5.0.1",
1938
+ "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
1939
+ "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
1940
+ "license": "MIT"
1941
+ },
1942
+ "node_modules/redux-thunk": {
1943
+ "version": "3.1.0",
1944
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz",
1945
+ "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
1946
+ "license": "MIT",
1947
+ "peerDependencies": {
1948
+ "redux": "^5.0.0"
1949
+ }
1950
+ },
1951
+ "node_modules/reselect": {
1952
+ "version": "5.1.1",
1953
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz",
1954
+ "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==",
1955
+ "license": "MIT"
1956
+ },
1957
+ "node_modules/rollup": {
1958
+ "version": "4.53.3",
1959
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz",
1960
+ "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==",
1961
+ "dev": true,
1962
+ "license": "MIT",
1963
+ "dependencies": {
1964
+ "@types/estree": "1.0.8"
1965
+ },
1966
+ "bin": {
1967
+ "rollup": "dist/bin/rollup"
1968
+ },
1969
+ "engines": {
1970
+ "node": ">=18.0.0",
1971
+ "npm": ">=8.0.0"
1972
+ },
1973
+ "optionalDependencies": {
1974
+ "@rollup/rollup-android-arm-eabi": "4.53.3",
1975
+ "@rollup/rollup-android-arm64": "4.53.3",
1976
+ "@rollup/rollup-darwin-arm64": "4.53.3",
1977
+ "@rollup/rollup-darwin-x64": "4.53.3",
1978
+ "@rollup/rollup-freebsd-arm64": "4.53.3",
1979
+ "@rollup/rollup-freebsd-x64": "4.53.3",
1980
+ "@rollup/rollup-linux-arm-gnueabihf": "4.53.3",
1981
+ "@rollup/rollup-linux-arm-musleabihf": "4.53.3",
1982
+ "@rollup/rollup-linux-arm64-gnu": "4.53.3",
1983
+ "@rollup/rollup-linux-arm64-musl": "4.53.3",
1984
+ "@rollup/rollup-linux-loong64-gnu": "4.53.3",
1985
+ "@rollup/rollup-linux-ppc64-gnu": "4.53.3",
1986
+ "@rollup/rollup-linux-riscv64-gnu": "4.53.3",
1987
+ "@rollup/rollup-linux-riscv64-musl": "4.53.3",
1988
+ "@rollup/rollup-linux-s390x-gnu": "4.53.3",
1989
+ "@rollup/rollup-linux-x64-gnu": "4.53.3",
1990
+ "@rollup/rollup-linux-x64-musl": "4.53.3",
1991
+ "@rollup/rollup-openharmony-arm64": "4.53.3",
1992
+ "@rollup/rollup-win32-arm64-msvc": "4.53.3",
1993
+ "@rollup/rollup-win32-ia32-msvc": "4.53.3",
1994
+ "@rollup/rollup-win32-x64-gnu": "4.53.3",
1995
+ "@rollup/rollup-win32-x64-msvc": "4.53.3",
1996
+ "fsevents": "~2.3.2"
1997
+ }
1998
+ },
1999
+ "node_modules/scheduler": {
2000
+ "version": "0.27.0",
2001
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
2002
+ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
2003
+ "license": "MIT"
2004
+ },
2005
+ "node_modules/semver": {
2006
+ "version": "6.3.1",
2007
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
2008
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
2009
+ "dev": true,
2010
+ "license": "ISC",
2011
+ "bin": {
2012
+ "semver": "bin/semver.js"
2013
+ }
2014
+ },
2015
+ "node_modules/source-map-js": {
2016
+ "version": "1.2.1",
2017
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
2018
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
2019
+ "dev": true,
2020
+ "license": "BSD-3-Clause",
2021
+ "engines": {
2022
+ "node": ">=0.10.0"
2023
+ }
2024
+ },
2025
+ "node_modules/tiny-invariant": {
2026
+ "version": "1.3.3",
2027
+ "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
2028
+ "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==",
2029
+ "license": "MIT"
2030
+ },
2031
+ "node_modules/tinyglobby": {
2032
+ "version": "0.2.15",
2033
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
2034
+ "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
2035
+ "dev": true,
2036
+ "license": "MIT",
2037
+ "dependencies": {
2038
+ "fdir": "^6.5.0",
2039
+ "picomatch": "^4.0.3"
2040
+ },
2041
+ "engines": {
2042
+ "node": ">=12.0.0"
2043
+ },
2044
+ "funding": {
2045
+ "url": "https://github.com/sponsors/SuperchupuDev"
2046
+ }
2047
+ },
2048
+ "node_modules/typescript": {
2049
+ "version": "5.8.3",
2050
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
2051
+ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
2052
+ "dev": true,
2053
+ "license": "Apache-2.0",
2054
+ "bin": {
2055
+ "tsc": "bin/tsc",
2056
+ "tsserver": "bin/tsserver"
2057
+ },
2058
+ "engines": {
2059
+ "node": ">=14.17"
2060
+ }
2061
+ },
2062
+ "node_modules/undici-types": {
2063
+ "version": "6.21.0",
2064
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
2065
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
2066
+ "dev": true,
2067
+ "license": "MIT"
2068
+ },
2069
+ "node_modules/update-browserslist-db": {
2070
+ "version": "1.1.4",
2071
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz",
2072
+ "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==",
2073
+ "dev": true,
2074
+ "funding": [
2075
+ {
2076
+ "type": "opencollective",
2077
+ "url": "https://opencollective.com/browserslist"
2078
+ },
2079
+ {
2080
+ "type": "tidelift",
2081
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
2082
+ },
2083
+ {
2084
+ "type": "github",
2085
+ "url": "https://github.com/sponsors/ai"
2086
+ }
2087
+ ],
2088
+ "license": "MIT",
2089
+ "dependencies": {
2090
+ "escalade": "^3.2.0",
2091
+ "picocolors": "^1.1.1"
2092
+ },
2093
+ "bin": {
2094
+ "update-browserslist-db": "cli.js"
2095
+ },
2096
+ "peerDependencies": {
2097
+ "browserslist": ">= 4.21.0"
2098
+ }
2099
+ },
2100
+ "node_modules/use-sync-external-store": {
2101
+ "version": "1.6.0",
2102
+ "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
2103
+ "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
2104
+ "license": "MIT",
2105
+ "peerDependencies": {
2106
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
2107
+ }
2108
+ },
2109
+ "node_modules/victory-vendor": {
2110
+ "version": "37.3.6",
2111
+ "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz",
2112
+ "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==",
2113
+ "license": "MIT AND ISC",
2114
+ "dependencies": {
2115
+ "@types/d3-array": "^3.0.3",
2116
+ "@types/d3-ease": "^3.0.0",
2117
+ "@types/d3-interpolate": "^3.0.1",
2118
+ "@types/d3-scale": "^4.0.2",
2119
+ "@types/d3-shape": "^3.1.0",
2120
+ "@types/d3-time": "^3.0.0",
2121
+ "@types/d3-timer": "^3.0.0",
2122
+ "d3-array": "^3.1.6",
2123
+ "d3-ease": "^3.0.1",
2124
+ "d3-interpolate": "^3.0.1",
2125
+ "d3-scale": "^4.0.2",
2126
+ "d3-shape": "^3.1.0",
2127
+ "d3-time": "^3.0.0",
2128
+ "d3-timer": "^3.0.1"
2129
+ }
2130
+ },
2131
+ "node_modules/vite": {
2132
+ "version": "6.4.1",
2133
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
2134
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
2135
+ "dev": true,
2136
+ "license": "MIT",
2137
+ "dependencies": {
2138
+ "esbuild": "^0.25.0",
2139
+ "fdir": "^6.4.4",
2140
+ "picomatch": "^4.0.2",
2141
+ "postcss": "^8.5.3",
2142
+ "rollup": "^4.34.9",
2143
+ "tinyglobby": "^0.2.13"
2144
+ },
2145
+ "bin": {
2146
+ "vite": "bin/vite.js"
2147
+ },
2148
+ "engines": {
2149
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
2150
+ },
2151
+ "funding": {
2152
+ "url": "https://github.com/vitejs/vite?sponsor=1"
2153
+ },
2154
+ "optionalDependencies": {
2155
+ "fsevents": "~2.3.3"
2156
+ },
2157
+ "peerDependencies": {
2158
+ "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
2159
+ "jiti": ">=1.21.0",
2160
+ "less": "*",
2161
+ "lightningcss": "^1.21.0",
2162
+ "sass": "*",
2163
+ "sass-embedded": "*",
2164
+ "stylus": "*",
2165
+ "sugarss": "*",
2166
+ "terser": "^5.16.0",
2167
+ "tsx": "^4.8.1",
2168
+ "yaml": "^2.4.2"
2169
+ },
2170
+ "peerDependenciesMeta": {
2171
+ "@types/node": {
2172
+ "optional": true
2173
+ },
2174
+ "jiti": {
2175
+ "optional": true
2176
+ },
2177
+ "less": {
2178
+ "optional": true
2179
+ },
2180
+ "lightningcss": {
2181
+ "optional": true
2182
+ },
2183
+ "sass": {
2184
+ "optional": true
2185
+ },
2186
+ "sass-embedded": {
2187
+ "optional": true
2188
+ },
2189
+ "stylus": {
2190
+ "optional": true
2191
+ },
2192
+ "sugarss": {
2193
+ "optional": true
2194
+ },
2195
+ "terser": {
2196
+ "optional": true
2197
+ },
2198
+ "tsx": {
2199
+ "optional": true
2200
+ },
2201
+ "yaml": {
2202
+ "optional": true
2203
+ }
2204
+ }
2205
+ },
2206
+ "node_modules/yallist": {
2207
+ "version": "3.1.1",
2208
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
2209
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
2210
+ "dev": true,
2211
+ "license": "ISC"
2212
+ }
2213
+ }
2214
+ }
package.json ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "3gpp-innovation-extractor",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "vite build",
9
+ "preview": "vite preview"
10
+ },
11
+ "dependencies": {
12
+ "dexie": "^4.2.1",
13
+ "dexie-react-hooks": "^4.2.0",
14
+ "lucide-react": "^0.555.0",
15
+ "react": "^19.2.0",
16
+ "react-dom": "^19.2.0",
17
+ "recharts": "^3.5.0"
18
+ },
19
+ "devDependencies": {
20
+ "@types/node": "^22.14.0",
21
+ "@vitejs/plugin-react": "^5.0.0",
22
+ "typescript": "~5.8.2",
23
+ "vite": "^6.2.0"
24
+ }
25
+ }
services/backendService.ts ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { DocumentFile, Innovation } from '../types';
2
+
3
+ const BACKEND_API_URL = 'http://localhost:8000';
4
+
5
+ export interface ProcessResponse {
6
+ id: string;
7
+ file_name: string;
8
+ answer: string;
9
+ classification: string;
10
+ // id: string;
11
+ // innovation_name: string;
12
+ // problem_id: string;
13
+ // problem_statement: string;
14
+ // context: string;
15
+ // proposed_solution: string;
16
+ // technical_classification: string;
17
+ // classification: string;
18
+ }
19
+
20
+ export const backendService = {
21
+ /**
22
+ * Sends a document to the backend for processing.
23
+ * The backend handles extraction, storage (SQLite), and mock refinement.
24
+ */
25
+ processDocument: async (file: DocumentFile, workingGroup: string, meeting: string): Promise<Innovation | null> => {
26
+ if (!file.url) {
27
+ console.warn(`Skipping file ${file.filename}: No URL`);
28
+ return null;
29
+ }
30
+
31
+ try {
32
+ const payload = {
33
+ file_id: file.id,
34
+ filename: file.filename,
35
+ working_group: workingGroup,
36
+ meeting: meeting,
37
+ type: file.type,
38
+ status: file.status || "Unknown",
39
+ agenda_item: file.agendaItem || "Unknown",
40
+ url: file.url
41
+ };
42
+
43
+ const response = await fetch(`${BACKEND_API_URL}/process`, {
44
+ method: 'POST',
45
+ headers: { 'Content-Type': 'application/json' },
46
+ body: JSON.stringify(payload)
47
+ });
48
+
49
+ if (!response.ok) {
50
+ console.error(`Backend processing failed for ${file.filename}: ${response.statusText}`);
51
+ return null;
52
+ }
53
+
54
+ const data: ProcessResponse = await response.json();
55
+
56
+ // Map response to Innovation type
57
+ return {
58
+ id: file.id,
59
+ file_name: file.filename,
60
+ answer: data.answer,
61
+ classification: "UNCLASSIFIED",
62
+ } as Innovation;
63
+
64
+ } catch (error) {
65
+ console.error(`Error processing document ${file.filename}:`, error);
66
+ return null;
67
+ }
68
+ },
69
+
70
+ getPatterns: async (): Promise<any[]> => {
71
+ try {
72
+ const response = await fetch(`${BACKEND_API_URL}/patterns`);
73
+ if (response.ok) {
74
+ return await response.json();
75
+ }
76
+ return [];
77
+ } catch (error) {
78
+ console.error("Error fetching patterns:", error);
79
+ return [];
80
+ }
81
+ },
82
+
83
+ analyzeContent: async (patternId: number, fileId?: string, text?: string): Promise<{ content: string; result_id: number; methodology: string; context: string; problem: string; pattern_name: string } | null> => {
84
+ try {
85
+ const response = await fetch(`${BACKEND_API_URL}/analyze`, {
86
+ method: 'POST',
87
+ headers: { 'Content-Type': 'application/json' },
88
+ body: JSON.stringify({
89
+ pattern_id: patternId,
90
+ file_id: fileId,
91
+ text: text
92
+ })
93
+ });
94
+
95
+ if (response.ok) {
96
+ const data = await response.json();
97
+ return { content: data.content, result_id: data.id, methodology: data.methodology, context: data.context, problem: data.problem, pattern_name: data.pattern_name };
98
+ }
99
+ return null;
100
+ } catch (error) {
101
+ console.error("Error analyzing content:", error);
102
+ return null;
103
+ }
104
+ },
105
+
106
+ saveClassification: async (resultId: number, classification: string): Promise<boolean> => {
107
+ try {
108
+ const response = await fetch(`${BACKEND_API_URL}/classify`, {
109
+ method: 'POST',
110
+ headers: { 'Content-Type': 'application/json' },
111
+ body: JSON.stringify({ result_id: resultId, classification })
112
+ });
113
+ return response.ok;
114
+ } catch (error) {
115
+ console.error("Error saving classification:", error);
116
+ return false;
117
+ }
118
+ },
119
+
120
+ fetchClassifiedInnovations: async (): Promise<any[]> => {
121
+ try {
122
+ const response = await fetch(`${BACKEND_API_URL}/results`);
123
+ if (response.ok) {
124
+ return await response.json();
125
+ }
126
+ return [];
127
+ } catch (error) {
128
+ console.error("Error fetching classified innovations:", error);
129
+ return [];
130
+ }
131
+ },
132
+
133
+ fetchAllFiles: async (): Promise<DocumentFile[]> => {
134
+ try {
135
+ const response = await fetch(`${BACKEND_API_URL}/get_all`);
136
+ if (response.ok) {
137
+ const rows = await response.json();
138
+ // Map tuple to DocumentFile:
139
+ // [file_id, working_group, meeting, type, status, agenda_item, content, filename, timestamp]
140
+ return rows.map((row: any) => ({
141
+ id: row[0],
142
+ filename: row[7],
143
+ size: 'Unknown',
144
+ type: row[3],
145
+ uploaded: true, // It's from DB, so treated as processed/uploaded
146
+ status: row[4],
147
+ agendaItem: row[5],
148
+ url: '' // Not stored explicitly usually, or maybe we don't need it for display
149
+ }));
150
+ }
151
+ return [];
152
+ } catch (error) {
153
+ console.error("Error fetching all files:", error);
154
+ return [];
155
+ }
156
+ }
157
+ };
tsconfig.json ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "experimentalDecorators": true,
5
+ "useDefineForClassFields": false,
6
+ "module": "ESNext",
7
+ "lib": [
8
+ "ES2022",
9
+ "DOM",
10
+ "DOM.Iterable"
11
+ ],
12
+ "skipLibCheck": true,
13
+ "types": [
14
+ "node"
15
+ ],
16
+ "moduleResolution": "bundler",
17
+ "isolatedModules": true,
18
+ "moduleDetection": "force",
19
+ "allowJs": true,
20
+ "jsx": "react-jsx",
21
+ "paths": {
22
+ "@/*": [
23
+ "./*"
24
+ ]
25
+ },
26
+ "allowImportingTsExtensions": true,
27
+ "noEmit": true
28
+ }
29
+ }
types.ts ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export enum Classification {
2
+ UNCLASSIFIED = 'UNCLASSIFIED',
3
+ DELETE = 'DELETE',
4
+ LOW = 'LOW',
5
+ MEDIUM = 'MEDIUM',
6
+ HIGH = 'HIGH',
7
+ }
8
+
9
+ export interface Innovation {
10
+ id: string;
11
+ file_name: string;
12
+ answer: string;
13
+ // problem_statement: string;
14
+ // innovation_potential: string;
15
+ // source_reference: string;
16
+ classification: Classification;
17
+ analysis_result?: string;
18
+ result_id?: number;
19
+
20
+ // Analysis metadata
21
+ methodology?: string;
22
+ context?: string;
23
+ problem?: string;
24
+ pattern_name?: string;
25
+ }
26
+
27
+ export interface ResultResponse {
28
+ id: number;
29
+ file_name: string;
30
+ content: string;
31
+ classification: Classification;
32
+ methodology: string;
33
+ context: string;
34
+ problem: string;
35
+ }
36
+
37
+ export interface MeetingDoc {
38
+ TDoc: string;
39
+ Title: string;
40
+ Type: string;
41
+ For: string;
42
+ "TDoc Status": string;
43
+ "Agenda item description": string;
44
+ URL: string;
45
+ }
46
+
47
+ export interface DocumentFile {
48
+ id: string;
49
+ filename: string;
50
+ size: string;
51
+ type: string;
52
+ uploaded: boolean;
53
+ // Optional metadata from API
54
+ status?: string;
55
+ agendaItem?: string;
56
+ url?: string;
57
+ }
58
+
59
+ export interface ProcessingBatch {
60
+ id: number;
61
+ files: DocumentFile[];
62
+ status: 'pending' | 'uploading' | 'processing' | 'completed';
63
+ }
64
+
65
+ export interface StatsData {
66
+ name: string;
67
+ value: number;
68
+ fill: string;
69
+ }
vite.config.ts ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import path from 'path';
2
+ import { defineConfig, loadEnv } from 'vite';
3
+ import react from '@vitejs/plugin-react';
4
+
5
+ export default defineConfig(({ mode }) => {
6
+ const env = loadEnv(mode, '.', '');
7
+ return {
8
+ server: {
9
+ port: 3000,
10
+ host: '0.0.0.0',
11
+ },
12
+ plugins: [react()],
13
+ define: {
14
+ 'process.env.API_KEY': JSON.stringify(env.GEMINI_API_KEY),
15
+ 'process.env.GEMINI_API_KEY': JSON.stringify(env.GEMINI_API_KEY)
16
+ },
17
+ resolve: {
18
+ alias: {
19
+ '@': path.resolve(__dirname, '.'),
20
+ }
21
+ }
22
+ };
23
+ });