muhammad1707 commited on
Commit
8421ec4
·
1 Parent(s): fe0fe70

Move master code to main

Browse files
.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
+ .env
15
+
16
+ # Editor directories and files
17
+ .vscode/*
18
+ !.vscode/extensions.json
19
+ .idea
20
+ .DS_Store
21
+ *.suo
22
+ *.ntvs*
23
+ *.njsproj
24
+ *.sln
25
+ *.sw?
App.tsx ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState, useEffect, useCallback } from 'react';
2
+ import { Chat, Message, ChatState } from './types';
3
+ import { createChat, getChats, getMessages, sendMessage, deleteChat } from './services/api';
4
+ import ChatSidebar from './components/ChatSidebar';
5
+ import ChatWindow from './components/ChatWindow';
6
+ import DocumentsModal from './components/DocumentsModal';
7
+
8
+ const App: React.FC = () => {
9
+ const [state, setState] = useState<ChatState>({
10
+ chats: [],
11
+ activeChat: null,
12
+ messages: [],
13
+ isLoading: false,
14
+ isSending: false,
15
+ error: null,
16
+ });
17
+
18
+ const [isDocsModalOpen, setIsDocsModalOpen] = useState(false);
19
+
20
+ // Listen for custom event to open docs modal
21
+ useEffect(() => {
22
+ const handleOpenModal = () => setIsDocsModalOpen(true);
23
+ window.addEventListener('open-documents-modal', handleOpenModal);
24
+ return () => window.removeEventListener('open-documents-modal', handleOpenModal);
25
+ }, []);
26
+
27
+ // Load chats on mount
28
+ useEffect(() => {
29
+ loadChats();
30
+ }, []);
31
+
32
+ // Load all chats from API
33
+ const loadChats = async () => {
34
+ try {
35
+ setState(prev => ({ ...prev, isLoading: true, error: null }));
36
+ const chats = await getChats();
37
+ setState(prev => ({ ...prev, chats, isLoading: false }));
38
+ } catch (err) {
39
+ setState(prev => ({
40
+ ...prev,
41
+ isLoading: false,
42
+ error: err instanceof Error ? err.message : 'Failed to load chats',
43
+ }));
44
+ }
45
+ };
46
+
47
+ // Load messages for a chat
48
+ const loadMessages = async (chatId: string) => {
49
+ try {
50
+ setState(prev => ({ ...prev, isLoading: true, error: null }));
51
+ const messages = await getMessages(chatId);
52
+ setState(prev => ({ ...prev, messages, isLoading: false }));
53
+ } catch (err) {
54
+ setState(prev => ({
55
+ ...prev,
56
+ isLoading: false,
57
+ error: err instanceof Error ? err.message : 'Failed to load messages',
58
+ }));
59
+ }
60
+ };
61
+
62
+ // Handle selecting a chat
63
+ const handleSelectChat = useCallback(async (chat: Chat) => {
64
+ setState(prev => ({ ...prev, activeChat: chat, messages: [] }));
65
+ await loadMessages(chat.id);
66
+ }, []);
67
+
68
+ // Handle creating a new chat
69
+ const handleNewChat = useCallback(async () => {
70
+ try {
71
+ setState(prev => ({ ...prev, isLoading: true, error: null }));
72
+ const chat = await createChat();
73
+ setState(prev => ({
74
+ ...prev,
75
+ chats: [chat, ...prev.chats],
76
+ activeChat: chat,
77
+ messages: [],
78
+ isLoading: false,
79
+ }));
80
+ } catch (err) {
81
+ setState(prev => ({
82
+ ...prev,
83
+ isLoading: false,
84
+ error: err instanceof Error ? err.message : 'Failed to create chat',
85
+ }));
86
+ }
87
+ }, []);
88
+
89
+ // Handle deleting a chat
90
+ const handleDeleteChat = useCallback(async (chatId: string) => {
91
+ try {
92
+ await deleteChat(chatId);
93
+ setState(prev => {
94
+ const newChats = prev.chats.filter(c => c.id !== chatId);
95
+ const newActiveChat = prev.activeChat?.id === chatId ? null : prev.activeChat;
96
+ const newMessages = prev.activeChat?.id === chatId ? [] : prev.messages;
97
+ return {
98
+ ...prev,
99
+ chats: newChats,
100
+ activeChat: newActiveChat,
101
+ messages: newMessages,
102
+ };
103
+ });
104
+ } catch (err) {
105
+ setState(prev => ({
106
+ ...prev,
107
+ error: err instanceof Error ? err.message : 'Failed to delete chat',
108
+ }));
109
+ }
110
+ }, []);
111
+
112
+ // Handle sending a message
113
+ const handleSendMessage = useCallback(async (content: string) => {
114
+ if (!state.activeChat) return;
115
+
116
+ const chatId = state.activeChat.id;
117
+
118
+ // Optimistically add user message
119
+ const tempUserMsg: Message = {
120
+ id: `temp-${Date.now()}`,
121
+ chat_id: chatId,
122
+ role: 'user',
123
+ content,
124
+ timestamp: new Date().toISOString(),
125
+ };
126
+
127
+ setState(prev => ({
128
+ ...prev,
129
+ messages: [...prev.messages, tempUserMsg],
130
+ isSending: true,
131
+ error: null,
132
+ }));
133
+
134
+ try {
135
+ const response = await sendMessage(chatId, content);
136
+
137
+ setState(prev => {
138
+ // Replace temp message with real messages
139
+ const messagesWithoutTemp = prev.messages.filter(m => m.id !== tempUserMsg.id);
140
+ const newMessages = [
141
+ ...messagesWithoutTemp,
142
+ response.user_message,
143
+ response.assistant_message,
144
+ ];
145
+
146
+ // Update chat title if it changed (first message)
147
+ const updatedChats = prev.chats.map(chat => {
148
+ if (chat.id === chatId && chat.title === 'New Chat') {
149
+ const newTitle = content.length > 50 ? content.slice(0, 50) + '...' : content;
150
+ return { ...chat, title: newTitle };
151
+ }
152
+ return chat;
153
+ });
154
+
155
+ // Update active chat title too
156
+ const updatedActiveChat = prev.activeChat && prev.activeChat.title === 'New Chat'
157
+ ? { ...prev.activeChat, title: content.length > 50 ? content.slice(0, 50) + '...' : content }
158
+ : prev.activeChat;
159
+
160
+ return {
161
+ ...prev,
162
+ messages: newMessages,
163
+ chats: updatedChats,
164
+ activeChat: updatedActiveChat,
165
+ isSending: false,
166
+ };
167
+ });
168
+ } catch (err) {
169
+ setState(prev => ({
170
+ ...prev,
171
+ messages: prev.messages.filter(m => m.id !== tempUserMsg.id),
172
+ isSending: false,
173
+ error: err instanceof Error ? err.message : 'Failed to send message',
174
+ }));
175
+ }
176
+ }, [state.activeChat]);
177
+
178
+ return (
179
+ <div className="h-screen flex bg-gray-100 overflow-hidden">
180
+ {/* Sidebar */}
181
+ <ChatSidebar
182
+ chats={state.chats}
183
+ activeChat={state.activeChat}
184
+ onSelectChat={handleSelectChat}
185
+ onNewChat={handleNewChat}
186
+ onDeleteChat={handleDeleteChat}
187
+ isLoading={state.isLoading}
188
+ />
189
+
190
+ {/* Main Chat Area */}
191
+ <ChatWindow
192
+ activeChat={state.activeChat}
193
+ messages={state.messages}
194
+ onSendMessage={handleSendMessage}
195
+ isSending={state.isSending}
196
+ isLoading={state.isLoading}
197
+ />
198
+
199
+ {/* Error Toast */}
200
+ {state.error && (
201
+ <div className="fixed bottom-4 right-4 max-w-md bg-red-500 text-white px-6 py-4 rounded-xl shadow-2xl flex items-center gap-3 animate-in slide-in-from-bottom-4 duration-300">
202
+ <svg className="w-5 h-5 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
203
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
204
+ </svg>
205
+ <span className="text-sm font-medium">{state.error}</span>
206
+ <button
207
+ onClick={() => setState(prev => ({ ...prev, error: null }))}
208
+ className="ml-2 hover:bg-red-600 p-1 rounded transition-colors"
209
+ >
210
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
211
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
212
+ </svg>
213
+ </button>
214
+ </div>
215
+ )}
216
+
217
+ {/* Documents Management Modal */}
218
+ <DocumentsModal
219
+ isOpen={isDocsModalOpen}
220
+ onClose={() => setIsDocsModalOpen(false)}
221
+ />
222
+ </div>
223
+ );
224
+ };
225
+
226
+ export default App;
README.md CHANGED
@@ -1,15 +1,20 @@
1
- ---
2
- title: Chat Bot Ai
3
- emoji: 💬
4
- colorFrom: yellow
5
- colorTo: purple
6
- sdk: gradio
7
- sdk_version: 5.42.0
8
- app_file: app.py
9
- pinned: false
10
- hf_oauth: true
11
- hf_oauth_scopes:
12
- - inference-api
13
- ---
14
-
15
- An example chatbot using [Gradio](https://gradio.app), [`huggingface_hub`](https://huggingface.co/docs/huggingface_hub/v0.22.2/en/index), and the [Hugging Face Inference API](https://huggingface.co/docs/api-inference/index).
 
 
 
 
 
 
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/temp/2
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`
back/.gitignore ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python
2
+ __pycache__/
3
+ *.pyc
4
+ *.pyo
5
+ *.pyd
6
+ .ipynb_checkpoints/
7
+
8
+ # Envs
9
+ venv/
10
+ .venv/
11
+ env/
12
+ env311/
13
+ .env
14
+ vector_db.pkl
15
+
16
+ # Ma'lumotlar bazalari va Vektor do'konlari
17
+ chroma_db/
18
+ chats.db
19
+
20
+ # Caches
21
+ .cache/
22
+ .huggingface/
23
+ hf_cache/
24
+ transformers_cache/
25
+ datasets/
26
+ wandb/
27
+
28
+ # OS / IDE
29
+ .DS_Store
30
+ Thumbs.db
31
+ .vscode/
32
+ .idea/
33
+
34
+ # Logs
35
+ *.log
36
+
37
+ # Node (agar bo‘lsa)
38
+ node_modules/
39
+ dist/
40
+ build/
41
+
42
+ # Logs
43
+ logs
44
+ *.log
45
+ npm-debug.log*
46
+ yarn-debug.log*
47
+ yarn-error.log*
48
+ pnpm-debug.log*
49
+ lerna-debug.log*
50
+
51
+ node_modules
52
+ dist
53
+ dist-ssr
54
+ *.local
55
+ !Dockerfile.local
56
+ .env
57
+
58
+ # Editor directories and files
59
+ .vscode/*
60
+ !.vscode/extensions.json
61
+ .idea
62
+ .DS_Store
63
+ *.suo
64
+ *.ntvs*
65
+ *.njsproj
66
+ *.sln
67
+ *.sw?
68
+
back/data/data.pdf ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ %PDF-1.4
2
+ %���� ReportLab Generated PDF document http://www.reportlab.com
3
+ 1 0 obj
4
+ <<
5
+ /F1 2 0 R /F2 3 0 R /F3 4 0 R
6
+ >>
7
+ endobj
8
+ 2 0 obj
9
+ <<
10
+ /BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
11
+ >>
12
+ endobj
13
+ 3 0 obj
14
+ <<
15
+ /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
16
+ >>
17
+ endobj
18
+ 4 0 obj
19
+ <<
20
+ /BaseFont /ZapfDingbats /Name /F3 /Subtype /Type1 /Type /Font
21
+ >>
22
+ endobj
23
+ 5 0 obj
24
+ <<
25
+ /Contents 9 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 8 0 R /Resources <<
26
+ /Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
27
+ >> /Rotate 0 /Trans <<
28
+
29
+ >>
30
+ /Type /Page
31
+ >>
32
+ endobj
33
+ 6 0 obj
34
+ <<
35
+ /PageMode /UseNone /Pages 8 0 R /Type /Catalog
36
+ >>
37
+ endobj
38
+ 7 0 obj
39
+ <<
40
+ /Author (\(anonymous\)) /CreationDate (D:20260130044309+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260130044309+00'00') /Producer (ReportLab PDF Library - www.reportlab.com)
41
+ /Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
42
+ >>
43
+ endobj
44
+ 8 0 obj
45
+ <<
46
+ /Count 1 /Kids [ 5 0 R ] /Type /Pages
47
+ >>
48
+ endobj
49
+ 9 0 obj
50
+ <<
51
+ /Filter [ /ASCII85Decode /FlateDecode ] /Length 1267
52
+ >>
53
+ stream
54
+ Gat=*gQ(#H&:NH>i1gt$$u``H2+S[ZBbGY8'J6OBeCn[oetn[C(YZ(]:a.?8]:uumYr6fNL3$s]1E;8XI-C(u=<dAl6Q^cRLbb2X+Y']]g$e-km-\g_/M]mp67#B*R=YWZOC=p;hLR<Pa0?Im-(Mpc:!Hh"R?JK,$'/$;cdle"r>j%0!et&i(6oVAW\0n7c!Ikb?(q-iqtDfuoNnqOX\bkK?!S2F;JWsGUNZ>P,r&-uZ_hcn2l\E.K2)cUeYu@c!l6Z`Zr:)L'Lt`0fn%U&pq1R9HcOIA,)0S;q]_nMJ\`d.6q#GG?O0YC+quaW,XG)mZItnKpD8r3Z9X-q0Um^$pd,tZMb=`D`>@'A[WS?ljZL'VdthMZ,EMk*QhkhM9-YSDJNk9QkQAuWWRXeJCC!83jBc>mnmd4\]$M1&!qj-l0pLTA!Ci"XC*/5tbchm<VI[RCV5gX-S1Gm)9k_-)<HV3a%""S+Og4+]Qn@:Kfi!E#3ar%b*Q2BabIUc94)M,>g)mB+pe(gW]J:41p+1pP2PHsX62i^#Y4H9=$U/#!X?0]>&)%^iJ2enZU->QQb>L3'39Uhk%Q]T5)b@j]OWO?nSXOk>/S@N5>K^Sp/Y:AB+(iuBabA-(HNYN@4;P4hdDM\UD5mDfG@=j4]]"GK9Z;ZB$#5^hC'V.a$J"QrBnF&b]rhJsqV^1M8FSs#WUh&YRF@jm*VSg(m1f1"B]R!uhuaY\$G,%mS]\i-iR&580Q29NVP0d'bTjm;l"1rXG<A1MRfo"s7ch2K_kk:^N8rQ[UW[t5h-K;M5TFlIhU2F69VdGmWN3H0-b:)MQQYZ$Zc$RSbOoIsNO?aNpFQ`U&P'rF8=t"#HX!ChpC!E$P_N2J=/C4tBjmoch9E3b$"gGD=b-pmUBn$a8XCj/+5g_op#BrPATb-!Wm>dmd>^]Rlp`gNZ3mXBPMbSXe+fPA=S4[-&e'D[)!gJ91dTB*1(O[)0C[!KHMaQ@R[mEN%Dma-cbG7/T[;`pLZ#!Bf,DQj-f_]4BnFC"(CJnkPL&r1e'G\DB0_3DpM6u083"1@0/3lOd3ZM+lQ)463u@7:@$4WWY9W`D([UY"=16rLE,K"L#A2-X%K:h1nbE)>r:>uATZ^bu2QHoX(o5*maG&[p1[b6DPB#QWYjt[14"78$PerYL9$PLO;g5BIH"lViR['3HB?dNjPW<Mkje]n",Ek"LN601Bi_1Y^V8sO3-9L"NiFc3(&SJucl68tsN'd+t8\'QG1[JlOTY#[S/"9[W~>endstream
55
+ endobj
56
+ xref
57
+ 0 10
58
+ 0000000000 65535 f
59
+ 0000000073 00000 n
60
+ 0000000124 00000 n
61
+ 0000000231 00000 n
62
+ 0000000343 00000 n
63
+ 0000000426 00000 n
64
+ 0000000629 00000 n
65
+ 0000000697 00000 n
66
+ 0000000980 00000 n
67
+ 0000001039 00000 n
68
+ trailer
69
+ <<
70
+ /ID
71
+ [<3a59c1fb718ad604e94c5d4b1c977f65><3a59c1fb718ad604e94c5d4b1c977f65>]
72
+ % ReportLab generated PDF document -- digest (http://www.reportlab.com)
73
+
74
+ /Info 7 0 R
75
+ /Root 6 0 R
76
+ /Size 10
77
+ >>
78
+ startxref
79
+ 2397
80
+ %%EOF
back/data/uploads/505152ba-108c-40f9-b7ae-3bace9bb46bd_cv-new.pdf ADDED
Binary file (59.7 kB). View file
 
back/ollama_client.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+
3
+ OLLAMA_URL = "http://localhost:11434/api/generate"
4
+
5
+ def ask_ollama(prompt: str, model="llama3.2:1b") -> str:
6
+ response = requests.post(
7
+ OLLAMA_URL,
8
+ json={
9
+ "model": model,
10
+ "prompt": prompt,
11
+ "stream": False,
12
+ "options": {
13
+ "temperature": 0.2
14
+ }
15
+ },
16
+ timeout=120
17
+ )
18
+ response.raise_for_status()
19
+ return response.json()["response"]
back/reproduce_tool.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import requests
3
+ import sys
4
+
5
+ # Create a dummy chat first
6
+ try:
7
+ chat_res = requests.post("http://localhost:4000/chats", json={"title": "Debug Tool Chat"})
8
+ chat_id = chat_res.json()["id"]
9
+ print(f"Created chat: {chat_id}")
10
+ except Exception as e:
11
+ print(f"Failed to create chat: {e}")
12
+ sys.exit(1)
13
+
14
+ # Send tool request
15
+ url = f"http://localhost:4000/chats/{chat_id}/messages"
16
+ payload = {"content": "Calculate 15% of 8550"}
17
+
18
+ print(f"Sending request to {url}...")
19
+ try:
20
+ res = requests.post(url, json=payload)
21
+ print(f"Status: {res.status_code}")
22
+ print(f"Response: {res.text}")
23
+ except Exception as e:
24
+ print(f"Request failed: {e}")
back/requirements.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ python-dotenv
2
+ pypdf
3
+ scikit-learn
4
+ chromadb
5
+ fastapi
6
+ uvicorn
7
+ pydantic
8
+ numpy
9
+ requests
10
+ google-genai
11
+ python-multipart
back/server.py ADDED
@@ -0,0 +1,980 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import pickle
4
+ import numpy as np
5
+ import sqlite3
6
+ import uuid
7
+ from datetime import datetime
8
+ from typing import List, Optional
9
+ from dotenv import load_dotenv
10
+ from pypdf import PdfReader
11
+ from google import genai
12
+ from google.genai import types
13
+ from sklearn.metrics.pairwise import cosine_similarity
14
+ # import chromadb - Moved to try/except block below
15
+
16
+
17
+ # ==============================
18
+ # 0. Sozlamalar
19
+ # ==============================
20
+ load_dotenv()
21
+
22
+ API_KEY = os.getenv("GEMINI_API_KEY")
23
+ if not API_KEY:
24
+ raise RuntimeError("GEMINI_API_KEY topilmadi!")
25
+
26
+ client = genai.Client(api_key=API_KEY)
27
+ # Chat modeli (tez va arzon variant)
28
+ GEMINI_CHAT_MODEL = "gemini-1.5-flash"
29
+ # Embedding modeli
30
+ GEMINI_EMBED_MODEL = "text-embedding-004"
31
+
32
+ CHROMA_DIR = "./chroma_db"
33
+ CHAT_DB_PATH = "./chats.db"
34
+
35
+ # Use PersistentClient (Modern API)
36
+ # Fallback for Python 3.14 compatibility
37
+ try:
38
+ import chromadb
39
+ chroma_client = chromadb.PersistentClient(path=CHROMA_DIR)
40
+ collection = chroma_client.get_or_create_collection(name="rag_docs")
41
+ RAG_AVAILABLE = True
42
+ except Exception as e:
43
+ print(f"WARNING: ChromaDB failed to initialize (likely Python version mismatch): {e}")
44
+ chromadb = None
45
+ chroma_client = None
46
+ collection = None
47
+ RAG_AVAILABLE = False
48
+
49
+
50
+ # ==============================
51
+ # 1. PDF -> TEXT
52
+ # ==============================
53
+ def load_pdf(path: str) -> str:
54
+ reader = PdfReader(path)
55
+ text = ""
56
+ for page in reader.pages:
57
+ page_text = page.extract_text()
58
+ if page_text:
59
+ text += page_text + "\n"
60
+ return text
61
+
62
+ # ==============================
63
+ # 2. TEXT -> CHUNKS
64
+ # ==============================
65
+ def chunk_text(text, chunk_size=300, overlap=200):
66
+ chunks = []
67
+ start = 0
68
+ while start < len(text):
69
+ end = start + chunk_size
70
+ chunks.append(text[start:end])
71
+ start = end - overlap
72
+ return chunks
73
+
74
+ # ==============================
75
+ # 3. CHUNKS -> EMBEDDINGS
76
+ # ==============================
77
+ def embed_texts(texts):
78
+ # Ollama embedding for a list of texts
79
+ embeddings = []
80
+ for text in texts:
81
+ response = client.models.embed_content(
82
+ model=GEMINI_EMBED_MODEL,
83
+ contents=text
84
+ )
85
+ embeddings.append(response.embedding.values)
86
+ return embeddings
87
+
88
+
89
+ # ==============================
90
+ # 4. VECTOR DB (SAVE / LOAD)
91
+ # ==============================
92
+
93
+
94
+ # ==============================
95
+ # 4. VECTOR DB (SAVE / LOAD)
96
+ # ==============================
97
+
98
+ def save_to_chroma(chunks, embeddings, doc_id):
99
+ if not RAG_AVAILABLE: return
100
+ """
101
+ Revised to include doc_id in metadata for deletion support.
102
+ """
103
+ ids = [f"{doc_id}_chunk_{i}" for i in range(len(chunks))]
104
+ metadatas = [{"chunk_index": i, "doc_id": doc_id} for i in range(len(chunks))]
105
+
106
+ collection.add(
107
+ documents=chunks,
108
+ embeddings=embeddings,
109
+ ids=ids,
110
+ metadatas=metadatas
111
+ )
112
+
113
+ def delete_from_chroma(doc_id):
114
+ if not RAG_AVAILABLE: return
115
+ """Delete all chunks associated with a document ID"""
116
+ try:
117
+ collection.delete(where={"doc_id": doc_id})
118
+ except Exception as e:
119
+ print(f"Error deleting from Chroma: {e}")
120
+
121
+
122
+ # ==============================
123
+ # 5. SIMILARITY SEARCH
124
+ # ==============================
125
+
126
+ # ==============================
127
+ # Helper for RAG Tool
128
+ # ==============================
129
+ def find_context(query, top_k=3):
130
+ if not RAG_AVAILABLE: return []
131
+ try:
132
+ query_embedding = embed_texts([query])[0]
133
+ results = collection.query(
134
+ query_embeddings=[query_embedding],
135
+ n_results=top_k
136
+ )
137
+ return results["documents"][0]
138
+ except Exception as e:
139
+ print(f"RAG Error: {e}")
140
+ return []
141
+
142
+ def retrieve_documents(query: str) -> str:
143
+ """
144
+ Retrieve relevant information from the uploaded documents based on the query.
145
+ Use this tool when the user asks questions about specific documents or content
146
+ that might be contained in the uploaded PDF files.
147
+ """
148
+ if not RAG_AVAILABLE:
149
+ return "System Notification: RAG system is currently unavailable."
150
+
151
+ contexts = find_context(query)
152
+ if not contexts:
153
+ return "No relevant information found in documents."
154
+ return "\n\n---\n\n".join(contexts)
155
+
156
+ # ... (init_db, CRUD, etc - skipped for brevity in tool call logic, assuming target content matches)
157
+
158
+
159
+
160
+
161
+
162
+ # ==============================
163
+ # 6. CHAT & DOCUMENT DATABASE SETUP
164
+ # ==============================
165
+
166
+ def init_db():
167
+ """Initialize SQLite database for chat and document persistence"""
168
+ conn = sqlite3.connect(CHAT_DB_PATH)
169
+ cursor = conn.cursor()
170
+
171
+ # Create chats table
172
+ cursor.execute("""
173
+ CREATE TABLE IF NOT EXISTS chats (
174
+ id TEXT PRIMARY KEY,
175
+ title TEXT NOT NULL,
176
+ created_at TEXT NOT NULL
177
+ )
178
+ """)
179
+
180
+ # Create messages table
181
+ cursor.execute("""
182
+ CREATE TABLE IF NOT EXISTS messages (
183
+ id TEXT PRIMARY KEY,
184
+ chat_id TEXT NOT NULL,
185
+ role TEXT NOT NULL,
186
+ content TEXT NOT NULL,
187
+ timestamp TEXT NOT NULL,
188
+ FOREIGN KEY (chat_id) REFERENCES chats(id) ON DELETE CASCADE
189
+ )
190
+ """)
191
+
192
+ # Create documents table
193
+ cursor.execute("""
194
+ CREATE TABLE IF NOT EXISTS documents (
195
+ id TEXT PRIMARY KEY,
196
+ filename TEXT NOT NULL,
197
+ upload_date TEXT NOT NULL,
198
+ status TEXT NOT NULL
199
+ )
200
+ """)
201
+
202
+ conn.commit()
203
+ conn.close()
204
+
205
+ # Initialize database
206
+ init_db()
207
+
208
+
209
+ # ==============================
210
+ # 7. CHAT CRUD OPERATIONS
211
+ # ==============================
212
+
213
+ def create_chat(title: str = "New Chat") -> dict:
214
+ """Create a new chat session"""
215
+ chat_id = str(uuid.uuid4())
216
+ created_at = datetime.now().isoformat()
217
+
218
+ conn = sqlite3.connect(CHAT_DB_PATH)
219
+ cursor = conn.cursor()
220
+ cursor.execute(
221
+ "INSERT INTO chats (id, title, created_at) VALUES (?, ?, ?)",
222
+ (chat_id, title, created_at)
223
+ )
224
+ conn.commit()
225
+ conn.close()
226
+
227
+ return {"id": chat_id, "title": title, "created_at": created_at}
228
+
229
+
230
+ def get_all_chats() -> List[dict]:
231
+ """Get all chats ordered by creation date descending"""
232
+ conn = sqlite3.connect(CHAT_DB_PATH)
233
+ conn.row_factory = sqlite3.Row
234
+ cursor = conn.cursor()
235
+ cursor.execute("SELECT * FROM chats ORDER BY created_at DESC")
236
+ rows = cursor.fetchall()
237
+ conn.close()
238
+
239
+ return [dict(row) for row in rows]
240
+
241
+
242
+ def get_chat_by_id(chat_id: str) -> Optional[dict]:
243
+ """Get a single chat by ID"""
244
+ conn = sqlite3.connect(CHAT_DB_PATH)
245
+ conn.row_factory = sqlite3.Row
246
+ cursor = conn.cursor()
247
+ cursor.execute("SELECT * FROM chats WHERE id = ?", (chat_id,))
248
+ row = cursor.fetchone()
249
+ conn.close()
250
+
251
+ return dict(row) if row else None
252
+
253
+
254
+ def update_chat_title(chat_id: str, title: str) -> bool:
255
+ """Update chat title"""
256
+ conn = sqlite3.connect(CHAT_DB_PATH)
257
+ cursor = conn.cursor()
258
+ cursor.execute("UPDATE chats SET title = ? WHERE id = ?", (title, chat_id))
259
+ affected = cursor.rowcount
260
+ conn.commit()
261
+ conn.close()
262
+
263
+ return affected > 0
264
+
265
+
266
+ def delete_chat(chat_id: str) -> bool:
267
+ """Delete a chat and all its messages"""
268
+ conn = sqlite3.connect(CHAT_DB_PATH)
269
+ cursor = conn.cursor()
270
+ cursor.execute("DELETE FROM messages WHERE chat_id = ?", (chat_id,))
271
+ cursor.execute("DELETE FROM chats WHERE id = ?", (chat_id,))
272
+ affected = cursor.rowcount
273
+ conn.commit()
274
+ conn.close()
275
+
276
+ return affected > 0
277
+
278
+
279
+ # ==============================
280
+ # 7.5. DOCUMENT CRUD OPERATIONS
281
+ # ==============================
282
+
283
+ def create_document_record(filename: str) -> dict:
284
+ doc_id = str(uuid.uuid4())
285
+ upload_date = datetime.now().isoformat()
286
+ status = "ready" # We process synchronously for now
287
+
288
+ conn = sqlite3.connect(CHAT_DB_PATH)
289
+ cursor = conn.cursor()
290
+ cursor.execute(
291
+ "INSERT INTO documents (id, filename, upload_date, status) VALUES (?, ?, ?, ?)",
292
+ (doc_id, filename, upload_date, status)
293
+ )
294
+ conn.commit()
295
+ conn.close()
296
+
297
+ return {
298
+ "id": doc_id,
299
+ "filename": filename,
300
+ "upload_date": upload_date,
301
+ "status": status
302
+ }
303
+
304
+ def get_all_documents() -> List[dict]:
305
+ conn = sqlite3.connect(CHAT_DB_PATH)
306
+ conn.row_factory = sqlite3.Row
307
+ cursor = conn.cursor()
308
+ cursor.execute("SELECT * FROM documents ORDER BY upload_date DESC")
309
+ rows = cursor.fetchall()
310
+ conn.close()
311
+ return [dict(row) for row in rows]
312
+
313
+ def delete_document_record(doc_id: str) -> bool:
314
+ conn = sqlite3.connect(CHAT_DB_PATH)
315
+ cursor = conn.cursor()
316
+ cursor.execute("DELETE FROM documents WHERE id = ?", (doc_id,))
317
+ affected = cursor.rowcount
318
+ conn.commit()
319
+ conn.close()
320
+ return affected > 0
321
+
322
+
323
+ # ==============================
324
+ # 8. MESSAGE CRUD OPERATIONS
325
+ # ==============================
326
+
327
+ def add_message(chat_id: str, role: str, content: str) -> dict:
328
+ """Add a message to a chat"""
329
+ message_id = str(uuid.uuid4())
330
+ timestamp = datetime.now().isoformat()
331
+
332
+ conn = sqlite3.connect(CHAT_DB_PATH)
333
+ cursor = conn.cursor()
334
+ cursor.execute(
335
+ "INSERT INTO messages (id, chat_id, role, content, timestamp) VALUES (?, ?, ?, ?, ?)",
336
+ (message_id, chat_id, role, content, timestamp)
337
+ )
338
+ conn.commit()
339
+ conn.close()
340
+
341
+ return {
342
+ "id": message_id,
343
+ "chat_id": chat_id,
344
+ "role": role,
345
+ "content": content,
346
+ "timestamp": timestamp
347
+ }
348
+
349
+
350
+ def get_chat_messages(chat_id: str) -> List[dict]:
351
+ """Get all messages for a chat ordered by timestamp"""
352
+ conn = sqlite3.connect(CHAT_DB_PATH)
353
+ conn.row_factory = sqlite3.Row
354
+ cursor = conn.cursor()
355
+ cursor.execute(
356
+ "SELECT * FROM messages WHERE chat_id = ? ORDER BY timestamp ASC",
357
+ (chat_id,)
358
+ )
359
+ rows = cursor.fetchall()
360
+ conn.close()
361
+
362
+ return [dict(row) for row in rows]
363
+
364
+
365
+ # ==============================
366
+ # 9. RAG-AWARE GENERATION
367
+ # ==============================
368
+
369
+ from tools import calculate_expression, get_current_weather
370
+ # from google.genai.types import Tool, GenerateContentConfig, FunctionDeclaration
371
+
372
+
373
+ # ==============================
374
+ # 9. RAG-AWARE GENERATION
375
+ # ==============================
376
+
377
+ SYSTEM_PROMPT = """You are a helpful assistant.
378
+ - Answer general greetings (like 'hi', 'hello') directly and briefly.
379
+ - Use `retrieve_documents` ONLY for questions about uploaded files.
380
+ - Use `calculate_expression` ONLY for math.
381
+ - Use `get_current_weather` ONLY for weather questions.
382
+ DO NOT use tools for simple conversation.
383
+ """
384
+
385
+
386
+
387
+ def generate_rag_response(question: str, context_list: List[str], chat_history: List[dict]) -> str:
388
+ """
389
+ Generate a response using RAG with conversation history and tools.
390
+ """
391
+ # --- ROUTING LAYER (For 1B model stability) ---
392
+ is_greeting = question.lower().strip() in ["hi", "hello", "hey", "salom", "qalay", "howdy"]
393
+ is_very_short = len(question.strip()) < 10
394
+
395
+ messages = [{"role": "system", "content": SYSTEM_PROMPT}]
396
+ history_messages = chat_history[-10:] if len(chat_history) > 10 else chat_history
397
+ for msg in history_messages:
398
+ messages.append({"role": msg["role"], "content": msg["content"]})
399
+ messages.append({"role": "user", "content": question})
400
+
401
+ # If it's just a greeting, don't even show tools to the 1B model
402
+ if is_greeting or (is_very_short and not any(char.isdigit() for char in question)):
403
+ print(f"--- Routing: Simple greeting detected. Skipping tools. ---")
404
+ try:
405
+ response = client.models.generate_content(
406
+ model=GEMINI_CHAT_MODEL,
407
+ contents=question,
408
+ config=types.GenerateContentConfig(
409
+ system_instruction="You are a friendly assistant. Greet the user normally and briefly.",
410
+ temperature=0,
411
+ ),
412
+ # messages=[{"role": "system", "content": "You are a friendly assistant. Greet the user normally and briefly."}, {"role": "user", "content": question}],
413
+ # options={'temperature': 0}
414
+ )
415
+ # return response.text
416
+ return (response.text or "Hello! How can I help you todayyy?").strip()
417
+ except Exception as e:
418
+ print(f"Gemini Routing Error: {e}")
419
+ return "Hello! How can I help you today?"
420
+
421
+ # --- STANDARD TOOL CALLING LAYER ---
422
+ # tools =[
423
+ # {
424
+ # 'type': 'function',
425
+ # 'function': {
426
+ # 'name': 'calculate_expression',
427
+ # 'description': 'Solve arithmetic math problems (e.g. 2+2).',
428
+ # 'parameters': {
429
+ # 'type': 'object',
430
+ # 'properties': {
431
+ # 'expression': {'type': 'string', 'description': 'The math expression'},
432
+ # },
433
+ # 'required': ['expression'],
434
+ # },
435
+ # },
436
+ # },
437
+ # {
438
+ # 'type': 'function',
439
+ # 'function': {
440
+ # 'name': 'get_current_weather',
441
+ # 'description': 'Get the current weather for a city.',
442
+ # 'parameters': {
443
+ # 'type': 'object',
444
+ # 'properties': {
445
+ # 'location': {'type': 'string', 'description': 'City name'},
446
+ # },
447
+ # 'required': ['location'],
448
+ # },
449
+ # },
450
+ # },
451
+ # {
452
+ # 'type': 'function',
453
+ # 'function': {
454
+ # 'name': 'retrieve_documents',
455
+ # 'description': 'Search for information in uploaded PDF documents.',
456
+ # 'parameters': {
457
+ # 'type': 'object',
458
+ # 'properties': {
459
+ # 'query': {'type': 'string', 'description': 'The search query'},
460
+ # },
461
+ # 'required': ['query'],
462
+ # },
463
+ # },
464
+ # },
465
+ # ]
466
+
467
+ tool = types.Tool(function_declarations=[
468
+ types.FunctionDeclaration(
469
+ name="calculate_expression",
470
+ description="Solve arithmetic math problems (e.g. 2+2).",
471
+ parameters_json_schema={
472
+ "type": "object",
473
+ "properties": {
474
+ "expression": {"type": "string", "description": "The math expression"},
475
+ },
476
+ "required": ["expression"],
477
+ },
478
+ ),
479
+ types.FunctionDeclaration(
480
+ name="get_current_weather",
481
+ description="Get the current weather for a city.",
482
+ parameters_json_schema={
483
+ "type": "object",
484
+ "properties": {
485
+ "location": {"type": "string", "description": "City name"},
486
+ },
487
+ "required": ["location"],
488
+ },
489
+ ),
490
+ types.FunctionDeclaration(
491
+ name="retrieve_documents",
492
+ description="Search for information in uploaded PDF documents.",
493
+ parameters_json_schema={
494
+ "type": "object",
495
+ "properties": {
496
+ "query": {"type": "string", "description": "The search query"},
497
+ },
498
+ "required": ["query"],
499
+ },
500
+ ),
501
+ ])
502
+
503
+
504
+ try:
505
+ print(f"--- Sending to Ollama: {question} ---")
506
+ available_functions = {
507
+ "calculate_expression": calculate_expression,
508
+ "get_current_weather": get_current_weather,
509
+ "retrieve_documents": retrieve_documents,
510
+ }
511
+
512
+ # Gemini uchun promptni “system + history + user” ko‘rinishida bitta textga yig’amiz
513
+ system_text = SYSTEM_PROMPT
514
+ history_text = ""
515
+ for msg in (chat_history[-10:] if len(chat_history) > 10 else chat_history):
516
+ history_text += f"{msg['role'].upper()}: {msg['content']}\n"
517
+
518
+ user_text = f"{history_text}\nUSER: {question}".strip()
519
+ response = client.models.generate_content(
520
+ model=GEMINI_CHAT_MODEL,
521
+ contents=user_text,
522
+ config=types.GenerateContentConfig(
523
+ system_instruction=system_text,
524
+ tools=[tool],
525
+ temperature=0,
526
+ automatic_function_calling=types.AutomaticFunctionCallingConfig(disable=False),
527
+ ),
528
+ # messages=messages,
529
+ # tools=tools,
530
+ # options={'temperature': 0}
531
+ )
532
+
533
+ print(f"Raw Ollama response content: {response.text}")
534
+
535
+ # 1. Native Tool Calls
536
+ if response.function_calls:
537
+ print(f"Native tool calls detected: {response.function_calls}")
538
+ available_functions = {
539
+ 'calculate_expression': calculate_expression,
540
+ 'get_current_weather': get_current_weather,
541
+ 'retrieve_documents': retrieve_documents,
542
+ }
543
+
544
+ # messages.append(response.message)
545
+
546
+ tool_outputs = []
547
+
548
+ for call in response.function_calls:
549
+ # google-genai SDK da odatda shu ko‘rinish:
550
+ func_name = getattr(call, "name", None)
551
+ func_args = getattr(call, "args", None)
552
+
553
+ # fallback (agar boshqa format bo‘lsa):
554
+ if func_name is None and hasattr(call, "function"):
555
+ func_name = getattr(call.function, "name", None)
556
+ func_args = getattr(call.function, "arguments", None)
557
+
558
+ if isinstance(func_args, str):
559
+ try:
560
+ func_args = json.loads(func_args)
561
+ except Exception:
562
+ func_args = {}
563
+
564
+ if func_args is None:
565
+ func_args = {}
566
+
567
+ if func_name not in available_functions:
568
+ tool_outputs.append(f"{func_name}: Unknown tool")
569
+ continue
570
+
571
+ try:
572
+ result = available_functions[func_name](**func_args)
573
+ except Exception as e:
574
+ result = f"Tool error: {e}"
575
+
576
+ tool_outputs.append(f"{func_name}({func_args}) => {result}")
577
+
578
+ followup_prompt = (
579
+ f"{user_text}\n\n"
580
+ "Tool results:\n"
581
+ + "\n".join(tool_outputs)
582
+ + "\n\nNow answer the user using the tool results."
583
+ )
584
+
585
+ final_response = client.models.generate_content(
586
+ model=GEMINI_CHAT_MODEL,
587
+ contents=followup_prompt,
588
+ config=types.GenerateContentConfig(
589
+ system_instruction=system_text,
590
+ temperature=0,
591
+ ),
592
+ )
593
+ return (final_response.text or "").strip()
594
+
595
+ # 2. Hard Fallback for math/tool hallucinations
596
+ content = response.text.strip() if response.text else ""
597
+ hallucination_keywords = ["calculate_expression", "syntax error", "expression", "parameters"]
598
+
599
+ if any(kw in content.lower() for kw in hallucination_keywords) and not any(char.isdigit() for char in question):
600
+ print(f"Detected tool hallucination in text: {content[:50]}...")
601
+ retry_response = client.models.generate_content(
602
+ model=GEMINI_CHAT_MODEL,
603
+ messages=[{"role": "system", "content": "You are a helpful assistant. Provide a natural response without mentioning tools or syntax."}, {"role": "user", "content": question}],
604
+ options={'temperature': 0}
605
+ )
606
+ return retry_response.text
607
+
608
+ return content
609
+
610
+ except Exception as e:
611
+ print(f"Ollama Error: {e}")
612
+ return f"Error generation response: {str(e)}"
613
+
614
+
615
+
616
+
617
+ # Legacy function - kept for backwards compatibility
618
+ def ask_gemini(question, context_list):
619
+ context = "\n\n".join(context_list)
620
+ prompt = f"""Quyidagi context ma'lumotlaridan foydalanib savolga javob ber.
621
+ Faqat context ichidagi ma'lumotni ishlat.
622
+
623
+ Context:
624
+ {context}
625
+
626
+ Savol: {question}"""
627
+
628
+ response = client.models.generate_content(
629
+ # messages=[{'role': 'user', 'content': prompt}]
630
+ model=GEMINI_CHAT_MODEL,
631
+ contents=prompt,
632
+ config=types.GenerateContentConfig(temperature=0),
633
+ )
634
+ return (response.text or "").strip()
635
+
636
+
637
+ # ==============================
638
+ # 10. MAIN PROCESS (PDF Processing)
639
+ # ==============================
640
+ if __name__ == "__main__":
641
+ # No hardcoded PDF loading anymore. Documents are managed via API.
642
+ print("RAG system initialized. Use API endpoints to manage documents and chats.")
643
+
644
+
645
+ # ==============================
646
+ # 11. FASTAPI APPLICATION
647
+ # ==============================
648
+
649
+ from fastapi import FastAPI, HTTPException, UploadFile, File
650
+ from fastapi.middleware.cors import CORSMiddleware
651
+ from pydantic import BaseModel
652
+
653
+
654
+ app = FastAPI(title="RAG Chat API", version="2.0.0")
655
+ app.add_middleware(
656
+ CORSMiddleware,
657
+ allow_origins=["*"],
658
+ allow_methods=["*"],
659
+ allow_headers=["*"],
660
+ )
661
+
662
+
663
+ # ==============================
664
+ # 12. REQUEST/RESPONSE MODELS
665
+ # ==============================
666
+
667
+ class QuestionRequest(BaseModel):
668
+ question: str
669
+
670
+ class CreateChatRequest(BaseModel):
671
+ title: Optional[str] = "New Chat"
672
+
673
+ class SendMessageRequest(BaseModel):
674
+ content: str
675
+
676
+ class UpdateChatRequest(BaseModel):
677
+ title: str
678
+
679
+
680
+ # ==============================
681
+ # 14.5 DOCUMENT ENDPOINTS
682
+ # ==============================
683
+
684
+ @app.get("/documents")
685
+ async def list_documents():
686
+ return {"documents": get_all_documents()}
687
+
688
+ @app.post("/documents")
689
+ async def upload_document(file: UploadFile = File(...)):
690
+ if not RAG_AVAILABLE:
691
+ raise HTTPException(status_code=503, detail="RAG system unavailable (Python 3.14 incompatibility).")
692
+
693
+ if not file.filename.endswith('.pdf'):
694
+ raise HTTPException(status_code=400, detail="Only PDF files are allowed")
695
+
696
+ # Save file temporarily
697
+ os.makedirs("data/uploads", exist_ok=True)
698
+ file_path = f"data/uploads/{uuid.uuid4()}_{file.filename}"
699
+
700
+ try:
701
+ with open(file_path, "wb") as f:
702
+ content = await file.read()
703
+ f.write(content)
704
+
705
+ # Process PDF
706
+ text = load_pdf(file_path)
707
+ if not text.strip():
708
+ raise HTTPException(status_code=400, detail="Could not extract text from PDF")
709
+
710
+ chunks = chunk_text(text)
711
+ embeddings = embed_texts(chunks)
712
+
713
+ # Save Metadata
714
+ doc = create_document_record(file.filename)
715
+
716
+ # Save Vectors
717
+ save_to_chroma(chunks, embeddings, doc["id"])
718
+
719
+ # Cleanup file (optional, keeping it for now in case needed, or delete)
720
+ # os.remove(file_path)
721
+
722
+ return doc
723
+
724
+ except Exception as e:
725
+ if os.path.exists(file_path):
726
+ os.remove(file_path)
727
+ raise HTTPException(status_code=500, detail=f"Processing failed: {str(e)}")
728
+
729
+ @app.delete("/documents/{doc_id}")
730
+ async def delete_document(doc_id: str):
731
+ if not RAG_AVAILABLE:
732
+ # Still allow deleting from DB, just skip vector delete
733
+ pass
734
+
735
+ success = delete_document_record(doc_id)
736
+ if not success:
737
+ raise HTTPException(status_code=404, detail="Document not found")
738
+
739
+ # Remove from Vector DB
740
+ if RAG_AVAILABLE:
741
+ delete_from_chroma(doc_id)
742
+
743
+ return {"message": "Document deleted successfully"}
744
+
745
+
746
+ # ==============================
747
+ # 13. LEGACY ENDPOINT (backwards compatibility)
748
+ # ==============================
749
+
750
+ @app.post("/ask")
751
+ async def ask_question(req: QuestionRequest):
752
+ """Legacy endpoint - still functional for backwards compatibility"""
753
+ question = req.question.strip()
754
+ if not question:
755
+ raise HTTPException(status_code=400, detail="Savol bo'sh bo'lishi mumkin emas")
756
+
757
+ # This endpoint now relies on documents already in ChromaDB, not auto-loading data.pdf
758
+ if collection.count() == 0:
759
+ raise HTTPException(status_code=404, detail="No documents loaded into the system. Please upload PDFs first.")
760
+
761
+ relevant_chunks = find_context(question, top_k=3)
762
+ answer = ask_gemini(question, relevant_chunks)
763
+
764
+ return {"answer": answer}
765
+
766
+
767
+ # ==============================
768
+ # 14. CHAT ENDPOINTS
769
+ # ==============================
770
+
771
+ @app.post("/chats")
772
+ async def create_new_chat(req: CreateChatRequest = CreateChatRequest()):
773
+ """Create a new chat session"""
774
+ chat = create_chat(req.title)
775
+ return chat
776
+
777
+
778
+ @app.get("/chats")
779
+ async def list_chats():
780
+ """Get all chats"""
781
+ chats = get_all_chats()
782
+ return {"chats": chats}
783
+
784
+
785
+ @app.get("/chats/{chat_id}")
786
+ async def get_chat(chat_id: str):
787
+ """Get a single chat by ID"""
788
+ chat = get_chat_by_id(chat_id)
789
+ if not chat:
790
+ raise HTTPException(status_code=404, detail="Chat not found")
791
+ return chat
792
+
793
+
794
+ @app.patch("/chats/{chat_id}")
795
+ async def update_chat(chat_id: str, req: UpdateChatRequest):
796
+ """Update chat title"""
797
+ success = update_chat_title(chat_id, req.title)
798
+ if not success:
799
+ raise HTTPException(status_code=404, detail="Chat not found")
800
+ return {"message": "Chat updated successfully"}
801
+
802
+
803
+ @app.delete("/chats/{chat_id}")
804
+ async def remove_chat(chat_id: str):
805
+ """Delete a chat and all its messages"""
806
+ success = delete_chat(chat_id)
807
+ if not success:
808
+ raise HTTPException(status_code=404, detail="Chat not found")
809
+ return {"message": "Chat deleted successfully"}
810
+
811
+
812
+ # ==============================
813
+ # 14.5 DOCUMENT ENDPOINTS
814
+ # ==============================
815
+
816
+ @app.get("/documents")
817
+ async def list_documents():
818
+ return {"documents": get_all_documents()}
819
+
820
+ @app.post("/documents")
821
+ async def upload_document(file: UploadFile = File(...)):
822
+ if not RAG_AVAILABLE:
823
+ raise HTTPException(status_code=503, detail="RAG system unavailable (Python 3.14 incompatibility).")
824
+
825
+ if not file.filename.endswith('.pdf'):
826
+ raise HTTPException(status_code=400, detail="Only PDF files are allowed")
827
+
828
+ # Save file temporarily
829
+ os.makedirs("data/uploads", exist_ok=True)
830
+ file_path = f"data/uploads/{uuid.uuid4()}_{file.filename}"
831
+
832
+ try:
833
+ with open(file_path, "wb") as f:
834
+ content = await file.read()
835
+ f.write(content)
836
+
837
+ # Process PDF
838
+ text = load_pdf(file_path)
839
+ if not text.strip():
840
+ raise HTTPException(status_code=400, detail="Could not extract text from PDF")
841
+
842
+ chunks = chunk_text(text)
843
+ embeddings = embed_texts(chunks)
844
+
845
+ # Save Metadata
846
+ doc = create_document_record(file.filename)
847
+
848
+ # Save Vectors
849
+ save_to_chroma(chunks, embeddings, doc["id"])
850
+
851
+ # Cleanup file (optional, keeping it for now in case needed, or delete)
852
+ # os.remove(file_path)
853
+
854
+ return doc
855
+
856
+ except Exception as e:
857
+ if os.path.exists(file_path):
858
+ os.remove(file_path)
859
+ raise HTTPException(status_code=500, detail=f"Processing failed: {str(e)}")
860
+
861
+ @app.delete("/documents/{doc_id}")
862
+ async def delete_document(doc_id: str):
863
+ success = delete_document_record(doc_id)
864
+ if not success:
865
+ raise HTTPException(status_code=404, detail="Document not found")
866
+
867
+ # Remove from Vector DB
868
+ if RAG_AVAILABLE:
869
+ delete_from_chroma(doc_id)
870
+
871
+ return {"message": "Document deleted successfully"}
872
+
873
+
874
+
875
+ # ==============================
876
+ # 15. MESSAGE ENDPOINTS
877
+ # ==============================
878
+
879
+ @app.get("/chats/{chat_id}/messages")
880
+ async def get_messages(chat_id: str):
881
+ """Get all messages for a chat"""
882
+ chat = get_chat_by_id(chat_id)
883
+ if not chat:
884
+ raise HTTPException(status_code=404, detail="Chat not found")
885
+
886
+ messages = get_chat_messages(chat_id)
887
+ return {"messages": messages}
888
+
889
+
890
+ @app.post("/chats/{chat_id}/messages")
891
+ async def send_message(chat_id: str, req: SendMessageRequest):
892
+ """
893
+ Send a message and get RAG-powered response.
894
+
895
+ This endpoint:
896
+ 1. Saves the user message
897
+ 2. Retrieves relevant context from vector DB
898
+ 3. Generates response using chat history + RAG context
899
+ 4. Saves and returns the assistant response
900
+ """
901
+ chat = get_chat_by_id(chat_id)
902
+ if not chat:
903
+ raise HTTPException(status_code=404, detail="Chat not found")
904
+
905
+ content = req.content.strip()
906
+ if not content:
907
+ raise HTTPException(status_code=400, detail="Message content cannot be empty")
908
+
909
+ # NO AUTO_LOAD of data.pdf anymore. RAG uses whatever is in Chroma.
910
+
911
+ # Save user message
912
+ user_message = add_message(chat_id, "user", content)
913
+
914
+ # Update chat title if this is the first message
915
+ messages = get_chat_messages(chat_id)
916
+ if len(messages) == 1: # Only the user message we just added
917
+ # Generate title from first message (truncate if too long)
918
+ title = content[:50] + "..." if len(content) > 50 else content
919
+ update_chat_title(chat_id, title)
920
+
921
+ # Get relevant context from RAG (Legacy/Fallback)
922
+ # The model will now use retrieve_documents tool if needed
923
+ relevant_chunks = []
924
+
925
+ # Get chat history (excluding the message we just added for cleaner history)
926
+ chat_history = messages[:-1] if len(messages) > 1 else []
927
+
928
+ # Generate RAG-powered response
929
+ response_text = generate_rag_response(content, relevant_chunks, chat_history)
930
+
931
+ # Save assistant message
932
+ assistant_message = add_message(chat_id, "assistant", response_text)
933
+
934
+ return {
935
+ "user_message": user_message,
936
+ "assistant_message": assistant_message
937
+ }
938
+
939
+
940
+ # ==============================
941
+ # 16. SERVER STARTUP
942
+ # ==============================
943
+
944
+ if __name__ == "__main__":
945
+ # Auto-load logic for data/data.pdf
946
+ DATA_PDF_PATH = os.path.abspath("../data/data.pdf")
947
+
948
+ # Create tables if not exist
949
+ init_db()
950
+
951
+ if RAG_AVAILABLE and os.path.exists(DATA_PDF_PATH):
952
+ print(f"Found default data file: {DATA_PDF_PATH}")
953
+ try:
954
+ # Check if likely already indexed (files with name 'data.pdf')
955
+ # This is a basic check.
956
+ conn = sqlite3.connect(CHAT_DB_PATH)
957
+ cursor = conn.cursor()
958
+ cursor.execute("SELECT id FROM documents WHERE filename = ?", ("data.pdf",))
959
+ existing = cursor.fetchone()
960
+ conn.close()
961
+
962
+ if not existing:
963
+ print("Auto-loading data.pdf...")
964
+ text = load_pdf(DATA_PDF_PATH)
965
+ if text.strip():
966
+ chunks = chunk_text(text)
967
+ embeddings = embed_texts(chunks)
968
+ doc = create_document_record("data.pdf")
969
+ save_to_chroma(chunks, embeddings, doc["id"])
970
+ print("Successfully auto-loaded data.pdf")
971
+ else:
972
+ print("Warning: data.pdf was empty")
973
+ else:
974
+ print("data.pdf already indexed.")
975
+
976
+ except Exception as e:
977
+ print(f"Failed to auto-load data.pdf: {e}")
978
+
979
+ import uvicorn
980
+ uvicorn.run("server:app", host="0.0.0.0", port=4000, reload=True)
back/test_chat.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import requests
3
+ import time
4
+
5
+ print("Waiting for server to ensure it is up...")
6
+ time.sleep(3)
7
+
8
+ try:
9
+ url = "http://localhost:4000/chats"
10
+ print(f"Testing POST {url}...")
11
+ res = requests.post(url, json={"title": "Test Chat"})
12
+ print(f"Status: {res.status_code}")
13
+ print(f"Response: {res.text}")
14
+ except Exception as e:
15
+ print(f"Failed to connect: {e}")
back/tools.py ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import math
3
+ import requests
4
+ import ast
5
+ import operator
6
+ from typing import Union, Dict, Any
7
+
8
+ # ==============================
9
+ # MATH TOOL
10
+ # ==============================
11
+
12
+ def calculate_expression(expression: str) -> Union[float, str]:
13
+ """
14
+ Safely evaluate a mathematical expression.
15
+ Supported operators: +, -, *, /, **, %, ^ (as power), sqrt, abs, round, sin, cos, tan, log, pi, e
16
+ """
17
+ # Safe operators map
18
+ operators = {
19
+ ast.Add: operator.add,
20
+ ast.Sub: operator.sub,
21
+ ast.Mult: operator.mul,
22
+ ast.Div: operator.truediv,
23
+ ast.Pow: operator.pow,
24
+ ast.Mod: operator.mod,
25
+ ast.USub: operator.neg,
26
+ ast.UAdd: operator.pos,
27
+ }
28
+
29
+ # Safe functions map
30
+ functions = {
31
+ "sqrt": math.sqrt,
32
+ "abs": abs,
33
+ "round": round,
34
+ "sin": math.sin,
35
+ "cos": math.cos,
36
+ "tan": math.tan,
37
+ "log": math.log,
38
+ "max": max,
39
+ "min": min,
40
+ "ceil": math.ceil,
41
+ "floor": math.floor,
42
+ "degrees": math.degrees,
43
+ "radians": math.radians,
44
+ }
45
+
46
+ # Safe constants
47
+ constants = {
48
+ "pi": math.pi,
49
+ "e": math.e,
50
+ "tau": math.tau,
51
+ }
52
+
53
+ def eval_node(node):
54
+ if isinstance(node, ast.Num): # < 3.8
55
+ return node.n
56
+ elif isinstance(node, ast.Constant): # >= 3.8
57
+ if isinstance(node.value, (int, float)):
58
+ return node.value
59
+ raise ValueError(f"Unsupported constant type: {type(node.value)}")
60
+ elif isinstance(node, ast.BinOp): # <left> <operator> <right>
61
+ op = type(node.op)
62
+ if op not in operators:
63
+ raise ValueError(f"Unsupported operator: {op}")
64
+ return operators[op](eval_node(node.left), eval_node(node.right))
65
+ elif isinstance(node, ast.UnaryOp): # <operator> <operand> (e.g., -1)
66
+ op = type(node.op)
67
+ if op not in operators:
68
+ raise ValueError(f"Unsupported unary operator: {op}")
69
+ return operators[op](eval_node(node.operand))
70
+ elif isinstance(node, ast.Call): # Function calls like sqrt(4)
71
+ if not isinstance(node.func, ast.Name):
72
+ raise ValueError("Only named functions are supported")
73
+ if node.func.id not in functions:
74
+ raise ValueError(f"Unsupported function: {node.func.id}")
75
+ args = [eval_node(arg) for arg in node.args]
76
+ return functions[node.func.id](*args)
77
+ elif isinstance(node, ast.Name): # Variables/Constants
78
+ if node.id in constants:
79
+ return constants[node.id]
80
+ raise ValueError(f"Unsupported name: {node.id}")
81
+ else:
82
+ raise TypeError(f"Unsupported expression node: {type(node)}")
83
+
84
+ try:
85
+ # Pre-process: replace ^ with ** for power
86
+ expression = expression.replace("^", "**")
87
+ node = ast.parse(expression, mode='eval')
88
+ result = eval_node(node.body)
89
+ return float(result)
90
+ except Exception as e:
91
+ return f"Error calculating '{expression}': {str(e)}"
92
+
93
+ # ==============================
94
+ # WEATHER TOOL
95
+ # ==============================
96
+
97
+ def get_current_weather(location: str) -> Dict[str, Any]:
98
+ """
99
+ Get current weather for a specific city using Open-Meteo API.
100
+ Returns temperature (C), humidity, wind speed, etc.
101
+ """
102
+ try:
103
+ # 1. Geocoding
104
+ geo_url = "https://geocoding-api.open-meteo.com/v1/search"
105
+ geo_params = {"name": location, "count": 1, "language": "en", "format": "json"}
106
+
107
+ geo_res = requests.get(geo_url, params=geo_params, timeout=5)
108
+ geo_data = geo_res.json()
109
+
110
+ if not geo_data.get("results"):
111
+ return {"error": f"City '{location}' not found."}
112
+
113
+ location = geo_data["results"][0]
114
+ lat = location["latitude"]
115
+ lon = location["longitude"]
116
+ city_name = location["name"]
117
+ country = location.get("country", "")
118
+
119
+ # 2. Weather Data
120
+ weather_url = "https://api.open-meteo.com/v1/forecast"
121
+ weather_params = {
122
+ "latitude": lat,
123
+ "longitude": lon,
124
+ "current": "temperature_2m,relative_humidity_2m,apparent_temperature,precipitation,rain,showers,snowfall,weather_code,cloud_cover,wind_speed_10m",
125
+ "timezone": "auto"
126
+ }
127
+
128
+ w_res = requests.get(weather_url, params=weather_params, timeout=5)
129
+ w_data = w_res.json()
130
+
131
+ if "current" not in w_data:
132
+ return {"error": "{location} Weather data not available."}
133
+
134
+ current = w_data["current"]
135
+ current_units = w_data["current_units"]
136
+
137
+ # Decode WMO Weather Code
138
+ # source: https://open-meteo.com/en/docs
139
+ wmo_code = current["weather_code"]
140
+ condition = "Unknown"
141
+ if wmo_code == 0: condition = "Clear sky"
142
+ elif 1 <= wmo_code <= 3: condition = "Mainly clear, partly cloudy, and overcast"
143
+ elif 45 <= wmo_code <= 48: condition = "Fog and depositing rime fog"
144
+ elif 51 <= wmo_code <= 55: condition = "Drizzle: Light, moderate, and dense intensity"
145
+ elif 56 <= wmo_code <= 57: condition = "Freezing Drizzle: Light and dense intensity"
146
+ elif 61 <= wmo_code <= 65: condition = "Rain: Slight, moderate and heavy intensity"
147
+ elif 66 <= wmo_code <= 67: condition = "Freezing Rain: Light and heavy intensity"
148
+ elif 71 <= wmo_code <= 75: condition = "Snow fall: Slight, moderate, and heavy intensity"
149
+ elif 77: condition = "Snow grains"
150
+ elif 80 <= wmo_code <= 82: condition = "Rain showers: Slight, moderate, and violent"
151
+ elif 85 <= wmo_code <= 86: condition = "Snow showers slight and heavy"
152
+ elif 95: condition = "Thunderstorm: Slight or moderate"
153
+ elif 96 <= wmo_code <= 99: condition = "Thunderstorm with slight and heavy hail"
154
+
155
+ return {
156
+ "location": f"{city_name}, {country}",
157
+ "temperature": f"{current['temperature_2m']} {current_units['temperature_2m']}",
158
+ "feels_like": f"{current['apparent_temperature']} {current_units['apparent_temperature']}",
159
+ "humidity": f"{current['relative_humidity_2m']} {current_units['relative_humidity_2m']}",
160
+ "wind_speed": f"{current['wind_speed_10m']} {current_units['wind_speed_10m']}",
161
+ "condition": condition,
162
+ "cloud_cover": f"{current['cloud_cover']} {current_units['cloud_cover']}",
163
+ "timestamp": current["time"]
164
+ }
165
+
166
+ except Exception as e:
167
+ return {"error": f"Failed to fetch weather: {str(e)}"}
back/verify_rag_tool.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import requests
3
+ import time
4
+
5
+ # Create chat
6
+ try:
7
+ chat = requests.post("http://localhost:4000/chats", json={"title": "RAG Tool Test"}).json()
8
+ chat_id = chat["id"]
9
+ except Exception as e:
10
+ print(f"Failed to create chat: {e}")
11
+ exit(1)
12
+
13
+ def ask(question):
14
+ print(f"\nUser: {question}")
15
+ t0 = time.time()
16
+ try:
17
+ res = requests.post(f"http://localhost:4000/chats/{chat_id}/messages", json={"content": question})
18
+ duration = time.time() - t0
19
+ if res.status_code == 200:
20
+ data = res.json()
21
+ print(f"Assistant ({duration:.1f}s): {data['assistant_message']['content']}")
22
+ else:
23
+ print(f"Error {res.status_code}: {res.text}")
24
+ except Exception as e:
25
+ print(f"Request failed: {e}")
26
+
27
+ # Test 1: Math Tool (Should verify tools still work)
28
+ ask("Calculate 55 * 4")
29
+
30
+ # Test 2: RAG Tool (Should verify retrieve_documents is called)
31
+ ask("What specific data is in the uploaded document?")
32
+
33
+ # Test 3: Rate Limit Resilience (Hammer the API)
34
+ print("\n--- Stress Test (Rate Limit) ---")
35
+ for i in range(5):
36
+ ask(f"Quick question {i}: What is 1+{i}?")
components/ChatInput.tsx ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState, useRef, useEffect } from 'react';
2
+
3
+ interface ChatInputProps {
4
+ onSendMessage: (content: string) => void;
5
+ isSending: boolean;
6
+ disabled: boolean;
7
+ }
8
+
9
+ const ChatInput: React.FC<ChatInputProps> = ({ onSendMessage, isSending, disabled }) => {
10
+ const [message, setMessage] = useState('');
11
+ const textareaRef = useRef<HTMLTextAreaElement>(null);
12
+
13
+ // Auto-resize textarea
14
+ useEffect(() => {
15
+ if (textareaRef.current) {
16
+ textareaRef.current.style.height = 'auto';
17
+ textareaRef.current.style.height = `${Math.min(textareaRef.current.scrollHeight, 200)}px`;
18
+ }
19
+ }, [message]);
20
+
21
+ const handleSubmit = () => {
22
+ const trimmed = message.trim();
23
+ if (trimmed && !isSending && !disabled) {
24
+ onSendMessage(trimmed);
25
+ setMessage('');
26
+ if (textareaRef.current) {
27
+ textareaRef.current.style.height = 'auto';
28
+ }
29
+ }
30
+ };
31
+
32
+ const handleKeyDown = (e: React.KeyboardEvent) => {
33
+ if (e.key === 'Enter' && !e.shiftKey) {
34
+ e.preventDefault();
35
+ handleSubmit();
36
+ }
37
+ };
38
+
39
+ return (
40
+ <div className="border-t border-gray-200 bg-white p-4">
41
+
42
+
43
+ <div className="max-w-4xl mx-auto">
44
+ <div className="relative flex items-end gap-3 bg-gray-50 border border-gray-200 rounded-2xl p-2 focus-within:border-indigo-300 focus-within:ring-2 focus-within:ring-indigo-100 transition-all">
45
+ <textarea
46
+ ref={textareaRef}
47
+ value={message}
48
+ onChange={(e) => setMessage(e.target.value)}
49
+ onKeyDown={handleKeyDown}
50
+ placeholder={disabled ? "Select or create a chat to start..." : "Ask a question..."}
51
+ disabled={disabled || isSending}
52
+ rows={1}
53
+ className="flex-1 resize-none bg-transparent px-3 py-2 text-gray-800 placeholder-gray-400 focus:outline-none text-sm leading-relaxed max-h-[200px] disabled:cursor-not-allowed"
54
+ />
55
+ <button
56
+ onClick={onsubmit}
57
+ disabled={!message.trim() || isSending || disabled}
58
+ className={`flex-shrink-0 p-3 rounded-xl transition-all duration-200 ${message.trim() && !isSending && !disabled
59
+ ? 'bg-gradient-to-r from-indigo-600 to-purple-600 text-white shadow-lg hover:shadow-indigo-500/30 hover:scale-105 active:scale-95'
60
+ : 'bg-gray-200 text-gray-400 cursor-not-allowed'
61
+ }`}
62
+ >
63
+ {isSending ? (
64
+ <svg className="w-5 h-5 animate-spin" fill="none" viewBox="0 0 24 24">
65
+ <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
66
+ <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
67
+ </svg>
68
+ ) : (
69
+ <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
70
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
71
+ </svg>
72
+ )}
73
+ </button>
74
+ </div>
75
+ <p className="text-xs text-gray-400 text-center mt-2">
76
+ Press Enter to send, Shift+Enter for new line
77
+ </p>
78
+ </div>
79
+ </div>
80
+ );
81
+ };
82
+
83
+ export default ChatInput;
components/ChatMessage.tsx ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+ import { Message } from '../types';
3
+
4
+ interface ChatMessageProps {
5
+ message: Message;
6
+ }
7
+
8
+ const ChatMessage: React.FC<ChatMessageProps> = ({ message }) => {
9
+ const isUser = message.role === 'user';
10
+
11
+ // Format timestamp
12
+ const formatTime = (timestamp: string) => {
13
+ const date = new Date(timestamp);
14
+ return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
15
+ };
16
+
17
+ return (
18
+ <div className={`flex gap-4 ${isUser ? 'flex-row-reverse' : 'flex-row'}`}>
19
+ {/* Avatar */}
20
+ <div className={`flex-shrink-0 w-10 h-10 rounded-full flex items-center justify-center text-white font-bold text-sm shadow-lg ${isUser
21
+ ? 'bg-gradient-to-br from-indigo-500 to-purple-600'
22
+ : 'bg-gradient-to-br from-emerald-500 to-teal-600'
23
+ }`}>
24
+ {isUser ? (
25
+ <svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
26
+ <path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" />
27
+ </svg>
28
+ ) : (
29
+ <svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
30
+ <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z" />
31
+ </svg>
32
+ )}
33
+ </div>
34
+
35
+ {/* Message Content */}
36
+ <div className={`flex flex-col max-w-[70%] ${isUser ? 'items-end' : 'items-start'}`}>
37
+ <div className={`px-4 py-3 rounded-2xl shadow-sm ${isUser
38
+ ? 'bg-gradient-to-r from-indigo-600 to-purple-600 text-white rounded-br-md'
39
+ : 'bg-white text-gray-800 border border-gray-100 rounded-bl-md'
40
+ }`}>
41
+ <p className="text-sm leading-relaxed whitespace-pre-wrap">
42
+ {message.content}
43
+ </p>
44
+ </div>
45
+ <span className={`text-xs mt-1 px-1 ${isUser ? 'text-gray-400' : 'text-gray-400'}`}>
46
+ {formatTime(message.timestamp)}
47
+ </span>
48
+ </div>
49
+ </div>
50
+ );
51
+ };
52
+
53
+ export default ChatMessage;
components/ChatSidebar.tsx ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from 'react';
2
+ import { Chat } from '../types';
3
+
4
+ interface ChatSidebarProps {
5
+ chats: Chat[];
6
+ activeChat: Chat | null;
7
+ onSelectChat: (chat: Chat) => void;
8
+ onNewChat: () => void;
9
+ onDeleteChat: (chatId: string) => void;
10
+ isLoading: boolean;
11
+ }
12
+
13
+ const ChatSidebar: React.FC<ChatSidebarProps> = ({
14
+ chats,
15
+ activeChat,
16
+ onSelectChat,
17
+ onNewChat,
18
+ onDeleteChat,
19
+ isLoading,
20
+ }) => {
21
+ return (
22
+ <aside className="w-72 bg-gray-900 flex flex-col h-full">
23
+ {/* Header */}
24
+ <div className="p-4 border-b border-gray-700">
25
+ <button
26
+ onClick={onNewChat}
27
+ disabled={isLoading}
28
+ className="w-full flex items-center justify-center gap-2 px-4 py-3 bg-gradient-to-r from-indigo-600 to-purple-600 hover:from-indigo-700 hover:to-purple-700 text-white font-semibold rounded-xl transition-all duration-200 shadow-lg hover:shadow-indigo-500/25 disabled:opacity-50 disabled:cursor-not-allowed"
29
+ >
30
+ <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
31
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
32
+ </svg>
33
+ New Chat
34
+ </button>
35
+ </div>
36
+
37
+ {/* Chat List */}
38
+ <div className="flex-1 overflow-y-auto py-2 scrollbar-thin scrollbar-thumb-gray-700 scrollbar-track-transparent">
39
+ {chats.length === 0 ? (
40
+ <div className="px-4 py-8 text-center text-gray-500 text-sm">
41
+ No chats yet. Start a new conversation!
42
+ </div>
43
+ ) : (
44
+ <div className="space-y-1 px-2">
45
+ {chats.map((chat) => (
46
+ <div
47
+ key={chat.id}
48
+ className={`group relative flex items-center gap-3 px-3 py-3 rounded-lg cursor-pointer transition-all duration-150 ${activeChat?.id === chat.id
49
+ ? 'bg-gray-700/80 text-white'
50
+ : 'text-gray-300 hover:bg-gray-800 hover:text-white'
51
+ }`}
52
+ onClick={() => onSelectChat(chat)}
53
+ >
54
+ <svg className="w-5 h-5 flex-shrink-0 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
55
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
56
+ </svg>
57
+ <span className="flex-1 truncate text-sm font-medium">
58
+ {chat.title}
59
+ </span>
60
+ {/* Delete button - shows on hover */}
61
+ <button
62
+ onClick={(e) => {
63
+ e.stopPropagation();
64
+ onDeleteChat(chat.id);
65
+ }}
66
+ className="opacity-0 group-hover:opacity-100 p-1 hover:bg-gray-600 rounded transition-all duration-150"
67
+ title="Delete chat"
68
+ >
69
+ <svg className="w-4 h-4 text-gray-400 hover:text-red-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
70
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
71
+ </svg>
72
+ </button>
73
+ </div>
74
+ ))}
75
+ </div>
76
+ )}
77
+ </div>
78
+
79
+ {/* Footer */}
80
+ <div className="p-4 border-t border-gray-700 space-y-3">
81
+ {/* Manage Documents Button */}
82
+ <button
83
+ onClick={() => window.dispatchEvent(new CustomEvent('open-documents-modal'))}
84
+ className="w-full flex items-center gap-3 px-3 py-2 text-gray-300 hover:text-white hover:bg-gray-800 rounded-lg transition-colors text-sm font-medium"
85
+ >
86
+ <div className="bg-gray-800 p-1.5 rounded-md group-hover:bg-gray-700">
87
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
88
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
89
+ </svg>
90
+ </div>
91
+ Manage Documents
92
+ </button>
93
+
94
+ <div className="flex items-center gap-2 text-xs text-gray-500 px-2 pt-2 border-t border-gray-800">
95
+ <div className="w-2 h-2 bg-green-500 rounded-full animate-pulse"></div>
96
+ <span>Created by Muhammadjon</span>
97
+ </div>
98
+ </div>
99
+ </aside>
100
+ );
101
+ };
102
+
103
+ export default ChatSidebar;
components/ChatWindow.tsx ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useRef, useEffect } from 'react';
2
+ import { Message, Chat } from '../types';
3
+ import ChatMessage from './ChatMessage';
4
+ import ChatInput from './ChatInput';
5
+
6
+ interface ChatWindowProps {
7
+ activeChat: Chat | null;
8
+ messages: Message[];
9
+ onSendMessage: (content: string) => void;
10
+ isSending: boolean;
11
+ isLoading: boolean;
12
+ }
13
+
14
+ const ChatWindow: React.FC<ChatWindowProps> = ({
15
+ activeChat,
16
+ messages,
17
+ onSendMessage,
18
+ isSending,
19
+ isLoading,
20
+ }) => {
21
+ const messagesEndRef = useRef<HTMLDivElement>(null);
22
+
23
+ // Auto-scroll to bottom when new messages arrive
24
+ useEffect(() => {
25
+ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
26
+ }, [messages]);
27
+
28
+ return (
29
+ <div className="flex-1 flex flex-col bg-gray-50 h-full">
30
+ {/* Header */}
31
+ <header className="bg-white border-b border-gray-200 px-6 py-4 flex items-center justify-between shadow-sm">
32
+ <div className="flex items-center gap-3">
33
+ <div className="bg-gradient-to-br from-indigo-500 to-purple-600 p-2 rounded-xl shadow-lg">
34
+ <svg className="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
35
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
36
+ </svg>
37
+ </div>
38
+ <div>
39
+ <h1 className="text-xl font-bold text-gray-900">
40
+ {activeChat ? activeChat.title : 'RAG Chat'}
41
+ </h1>
42
+ <p className="text-xs text-gray-500">Powered by AI + Document Retrieval</p>
43
+ </div>
44
+ </div>
45
+ {activeChat && (
46
+ <div className="flex items-center gap-2 text-xs text-gray-400">
47
+ <span className="w-2 h-2 bg-green-500 rounded-full animate-pulse"></span>
48
+ Online
49
+ </div>
50
+ )}
51
+ </header>
52
+
53
+ {/* Messages Area */}
54
+ <div className="flex-1 overflow-y-auto px-6 py-6">
55
+ {!activeChat ? (
56
+ // No Chat Selected State
57
+ <div className="h-full flex flex-col items-center justify-center text-center">
58
+ <div className="bg-gradient-to-br from-indigo-100 to-purple-100 p-6 rounded-3xl mb-6">
59
+ <svg className="w-16 h-16 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
60
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
61
+ </svg>
62
+ </div>
63
+ <h2 className="text-2xl font-bold text-gray-800 mb-2">Welcome to RAG Chat</h2>
64
+ <p className="text-gray-500 max-w-md mb-6">
65
+ Start a new conversation or select an existing chat from the sidebar to continue your discussion.
66
+ </p>
67
+ <div className="flex flex-wrap justify-center gap-3 text-sm">
68
+ <div className="bg-white px-4 py-2 rounded-full border border-gray-200 text-gray-600">
69
+ 💡 Ask questions about your documents
70
+ </div>
71
+ <div className="bg-white px-4 py-2 rounded-full border border-gray-200 text-gray-600">
72
+ 📚 Context-aware responses
73
+ </div>
74
+ <div className="bg-white px-4 py-2 rounded-full border border-gray-200 text-gray-600">
75
+ 💬 Conversation history
76
+ </div>
77
+ </div>
78
+ </div>
79
+ ) : isLoading ? (
80
+ // Loading Messages
81
+ <div className="h-full flex items-center justify-center">
82
+ <div className="flex flex-col items-center gap-4">
83
+ <div className="relative">
84
+ <div className="w-12 h-12 border-4 border-indigo-200 rounded-full animate-spin border-t-indigo-600"></div>
85
+ </div>
86
+ <span className="text-gray-500 text-sm">Loading messages...</span>
87
+ </div>
88
+ </div>
89
+ ) : messages.length === 0 ? (
90
+ // Empty Chat State
91
+ <div className="h-full flex flex-col items-center justify-center text-center">
92
+ <div className="bg-gradient-to-br from-emerald-100 to-teal-100 p-5 rounded-2xl mb-4">
93
+ <svg className="w-12 h-12 text-emerald-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
94
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M7 8h10M7 12h4m1 8l-4-4H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-3l-4 4z" />
95
+ </svg>
96
+ </div>
97
+ <h3 className="text-lg font-semibold text-gray-800 mb-1">Start the conversation</h3>
98
+ <p className="text-gray-500 text-sm max-w-sm">
99
+ Ask any question and I'll search through the documents to provide you with relevant answers.
100
+ </p>
101
+ </div>
102
+ ) : (
103
+ // Messages List
104
+ <div className="max-w-4xl mx-auto space-y-6">
105
+ {messages.map((msg) => (
106
+ <ChatMessage key={msg.id} message={msg} />
107
+ ))}
108
+
109
+ {/* Typing Indicator */}
110
+ {isSending && (
111
+ <div className="flex gap-4">
112
+ <div className="flex-shrink-0 w-10 h-10 rounded-full bg-gradient-to-br from-emerald-500 to-teal-600 flex items-center justify-center shadow-lg">
113
+ <svg className="w-5 h-5 text-white" fill="currentColor" viewBox="0 0 24 24">
114
+ <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z" />
115
+ </svg>
116
+ </div>
117
+ <div className="bg-white border border-gray-100 px-4 py-3 rounded-2xl rounded-bl-md shadow-sm">
118
+ <div className="flex gap-1">
119
+ <span className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: '0ms' }}></span>
120
+ <span className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: '150ms' }}></span>
121
+ <span className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: '300ms' }}></span>
122
+ </div>
123
+ </div>
124
+ </div>
125
+ )}
126
+
127
+ <div ref={messagesEndRef} />
128
+ </div>
129
+ )}
130
+ </div>
131
+
132
+ {/* Input Area */}
133
+ <ChatInput
134
+ onSendMessage={onSendMessage}
135
+ isSending={isSending}
136
+ disabled={!activeChat}
137
+ />
138
+ </div>
139
+ );
140
+ };
141
+
142
+ export default ChatWindow;
components/DocumentsModal.tsx ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState, useEffect, useRef } from 'react';
2
+ import { Document } from '../types';
3
+ import { getDocuments, uploadDocument, deleteDocument } from '../services/api';
4
+
5
+ interface DocumentsModalProps {
6
+ isOpen: boolean;
7
+ onClose: () => void;
8
+ }
9
+
10
+ const DocumentsModal: React.FC<DocumentsModalProps> = ({ isOpen, onClose }) => {
11
+ const [documents, setDocuments] = useState<Document[]>([]);
12
+ const [isLoading, setIsLoading] = useState(false);
13
+ const [isUploading, setIsUploading] = useState(false);
14
+ const [error, setError] = useState<string | null>(null);
15
+ const fileInputRef = useRef<HTMLInputElement>(null);
16
+
17
+ useEffect(() => {
18
+ if (isOpen) {
19
+ loadDocuments();
20
+ }
21
+ }, [isOpen]);
22
+
23
+ const loadDocuments = async () => {
24
+ try {
25
+ setIsLoading(true);
26
+ setError(null);
27
+ const docs = await getDocuments();
28
+ setDocuments(docs);
29
+ } catch (err) {
30
+ setError('Failed to load documents');
31
+ } finally {
32
+ setIsLoading(false);
33
+ }
34
+ };
35
+
36
+ const handleFileSelect = async (e: React.ChangeEvent<HTMLInputElement>) => {
37
+ if (e.target.files && e.target.files[0]) {
38
+ const file = e.target.files[0];
39
+ if (file.type !== 'application/pdf') {
40
+ setError('Only PDF files are allowed');
41
+ return;
42
+ }
43
+
44
+ try {
45
+ setIsUploading(true);
46
+ setError(null);
47
+ await uploadDocument(file);
48
+ await loadDocuments(); // Reload list
49
+ } catch (err) {
50
+ setError(err instanceof Error ? err.message : 'Upload failed');
51
+ } finally {
52
+ setIsUploading(false);
53
+ // Reset input
54
+ if (fileInputRef.current) fileInputRef.current.value = '';
55
+ }
56
+ }
57
+ };
58
+
59
+ const handleDelete = async (docId: string) => {
60
+ try {
61
+ if (!confirm('Are you sure you want to delete this document?')) return;
62
+
63
+ setIsLoading(true);
64
+ await deleteDocument(docId);
65
+ await loadDocuments();
66
+ } catch (err) {
67
+ setError(err instanceof Error ? err.message : 'Delete failed');
68
+ } finally {
69
+ setIsLoading(false);
70
+ }
71
+ };
72
+
73
+ if (!isOpen) return null;
74
+
75
+ return (
76
+ <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
77
+ <div className="bg-white rounded-2xl w-full max-w-2xl max-h-[80vh] flex flex-col shadow-2xl animate-in fade-in zoom-in-95 duration-200">
78
+
79
+ {/* Header */}
80
+ <div className="p-6 border-b border-gray-100 flex items-center justify-between">
81
+ <div>
82
+ <h2 className="text-xl font-bold text-gray-900">Manage Documents</h2>
83
+ <p className="text-sm text-gray-500 mt-1">Upload PDFs to include in the RAG knowledge base</p>
84
+ </div>
85
+ <button onClick={onClose} className="p-2 hover:bg-gray-100 rounded-full transition-colors text-gray-500">
86
+ <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
87
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
88
+ </svg>
89
+ </button>
90
+ </div>
91
+
92
+ {/* Content */}
93
+ <div className="flex-1 overflow-y-auto p-6">
94
+
95
+ {/* Upload Area */}
96
+ <div className="mb-8">
97
+ <input
98
+ type="file"
99
+ ref={fileInputRef}
100
+ accept=".pdf"
101
+ onChange={handleFileSelect}
102
+ className="hidden"
103
+ />
104
+ <button
105
+ onClick={() => fileInputRef.current?.click()}
106
+ disabled={isUploading}
107
+ className={`w-full border-2 border-dashed border-indigo-200 bg-indigo-50/50 rounded-xl p-8 flex flex-col items-center justify-center transition-all ${isUploading ? 'cursor-not-allowed opacity-75' : 'hover:border-indigo-400 hover:bg-indigo-50 cursor-pointer'
108
+ }`}
109
+ >
110
+ {isUploading ? (
111
+ <>
112
+ <div className="w-10 h-10 border-4 border-indigo-200 border-t-indigo-600 rounded-full animate-spin mb-3"></div>
113
+ <span className="text-indigo-600 font-medium">Processing Document...</span>
114
+ <span className="text-xs text-indigo-400 mt-1">Extracting text & generating embeddings</span>
115
+ </>
116
+ ) : (
117
+ <>
118
+ <div className="w-12 h-12 bg-indigo-100 text-indigo-600 rounded-full flex items-center justify-center mb-3">
119
+ <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
120
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" />
121
+ </svg>
122
+ </div>
123
+ <span className="text-gray-900 font-medium">Click to upload PDF</span>
124
+ <span className="text-xs text-gray-500 mt-1">Maximum file size: 10MB</span>
125
+ </>
126
+ )}
127
+ </button>
128
+ </div>
129
+
130
+ {/* Error Message */}
131
+ {error && (
132
+ <div className="mb-6 p-4 bg-red-50 text-red-600 rounded-xl text-sm flex items-center gap-2 border border-red-100">
133
+ <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
134
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
135
+ </svg>
136
+ {error}
137
+ </div>
138
+ )}
139
+
140
+ {/* Document List */}
141
+ <div>
142
+ <h3 className="text-sm font-semibold text-gray-900 uppercase tracking-wider mb-3">Uploaded Documents</h3>
143
+
144
+ {isLoading && documents.length === 0 ? (
145
+ <div className="text-center py-8 text-gray-400">Loading...</div>
146
+ ) : documents.length === 0 ? (
147
+ <div className="text-center py-8 text-gray-400 bg-gray-50 rounded-xl border border-gray-100 border-dashed">
148
+ No documents uploaded yet.
149
+ </div>
150
+ ) : (
151
+ <div className="space-y-2">
152
+ {documents.map((doc) => (
153
+ <div key={doc.id} className="flex items-center justify-between p-3 bg-white border border-gray-200 rounded-lg hover:border-indigo-200 transition-colors">
154
+ <div className="flex items-center gap-3 overflow-hidden">
155
+ <div className="w-10 h-10 bg-red-100 text-red-600 rounded-lg flex-shrink-0 flex items-center justify-center">
156
+ <svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
157
+ <path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zM6 20V4h7v5h5v11H6z" />
158
+ </svg>
159
+ </div>
160
+ <div className="min-w-0">
161
+ <h4 className="text-sm font-medium text-gray-900 truncate">{doc.filename}</h4>
162
+ <p className="text-xs text-gray-500">
163
+ {new Date(doc.upload_date).toLocaleDateString()} • {doc.status}
164
+ </p>
165
+ </div>
166
+ </div>
167
+
168
+ <button
169
+ onClick={() => handleDelete(doc.id)}
170
+ className="p-2 text-gray-400 hover:text-red-500 hover:bg-red-50 rounded-lg transition-colors"
171
+ title="Delete Document"
172
+ >
173
+ <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
174
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
175
+ </svg>
176
+ </button>
177
+ </div>
178
+ ))}
179
+ </div>
180
+ )}
181
+ </div>
182
+ </div>
183
+
184
+ {/* Footer */}
185
+ <div className="p-4 border-t border-gray-100 bg-gray-50 rounded-b-2xl">
186
+ <p className="text-xs text-center text-gray-500">
187
+ Documents are processed locally. Embeddings are stored in ChromaDB vector store.
188
+ </p>
189
+ </div>
190
+ </div>
191
+ </div>
192
+ );
193
+ };
194
+
195
+ export default DocumentsModal;
components/Header.tsx ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import React from 'react';
3
+
4
+ const Header: React.FC = () => {
5
+ return (
6
+ <header className="py-8 px-4 border-b border-gray-200 bg-white">
7
+ <div className="max-w-4xl mx-auto flex items-center justify-between">
8
+ <div className="flex items-center gap-3">
9
+ <div className="bg-indigo-600 p-2 rounded-lg">
10
+ <svg className="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
11
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16m-7 6h7" />
12
+ </svg>
13
+ </div>
14
+ <div>
15
+ <h1 className="text-2xl font-bold text-gray-900 tracking-tight">Briefly AI</h1>
16
+ <p className="text-sm text-gray-500 font-medium">Smart Professional Summarization</p>
17
+ </div>
18
+ </div>
19
+ <div className="hidden sm:flex items-center gap-4">
20
+ {/* <span className="px-3 py-1 bg-green-100 text-green-700 text-xs font-bold rounded-full uppercase">Powered by Gemini</span> */}
21
+ </div>
22
+ </div>
23
+ </header>
24
+ );
25
+ };
26
+
27
+ export default Header;
components/SummaryResult.tsx ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import React, { useState } from 'react';
3
+
4
+ interface SummaryResultProps {
5
+ summary: string;
6
+ }
7
+
8
+ const SummaryResult: React.FC<SummaryResultProps> = ({ summary }) => {
9
+ const [copied, setCopied] = useState(false);
10
+
11
+ const handleCopy = () => {
12
+ navigator.clipboard.writeText(summary);
13
+ setCopied(true);
14
+ setTimeout(() => setCopied(false), 2000);
15
+ };
16
+
17
+ if (!summary) return null;
18
+
19
+ return (
20
+ <div className="mt-8 animate-in fade-in slide-in-from-bottom-4 duration-500">
21
+ <div className="flex items-center justify-between mb-4">
22
+ <h2 className="text-lg font-semibold text-gray-800 flex items-center gap-2">
23
+ <svg className="w-5 h-5 text-indigo-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
24
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
25
+ </svg>
26
+ Summary
27
+ </h2>
28
+ <button
29
+ onClick={handleCopy}
30
+ className="text-sm flex items-center gap-1.5 font-medium text-indigo-600 hover:text-indigo-700 transition-colors px-3 py-1 rounded-md hover:bg-indigo-50"
31
+ >
32
+ {copied ? (
33
+ <>
34
+ <svg className="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
35
+ <path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
36
+ </svg>
37
+ Copied
38
+ </>
39
+ ) : (
40
+ <>
41
+ <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
42
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3" />
43
+ </svg>
44
+ Copy Text
45
+ </>
46
+ )}
47
+ </button>
48
+ </div>
49
+ <div className="bg-white border border-gray-200 rounded-xl p-6 shadow-sm">
50
+ <div className="prose prose-indigo max-w-none text-gray-700 leading-relaxed">
51
+ {summary}
52
+ </div>
53
+ </div>
54
+ </div>
55
+ );
56
+ };
57
+
58
+ export default SummaryResult;
index.css ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Global Styles for RAG Chat Application */
2
+
3
+ /* Scrollbar Styling */
4
+ .scrollbar-thin {
5
+ scrollbar-width: thin;
6
+ }
7
+
8
+ .scrollbar-thin::-webkit-scrollbar {
9
+ width: 6px;
10
+ }
11
+
12
+ .scrollbar-thin::-webkit-scrollbar-track {
13
+ background: transparent;
14
+ }
15
+
16
+ .scrollbar-thin::-webkit-scrollbar-thumb {
17
+ background-color: rgba(107, 114, 128, 0.5);
18
+ border-radius: 3px;
19
+ }
20
+
21
+ .scrollbar-thin::-webkit-scrollbar-thumb:hover {
22
+ background-color: rgba(107, 114, 128, 0.7);
23
+ }
24
+
25
+ /* Animation Classes */
26
+ @keyframes slideInFromBottom {
27
+ from {
28
+ opacity: 0;
29
+ transform: translateY(10px);
30
+ }
31
+ to {
32
+ opacity: 1;
33
+ transform: translateY(0);
34
+ }
35
+ }
36
+
37
+ .animate-in {
38
+ animation-duration: 300ms;
39
+ animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
40
+ animation-fill-mode: both;
41
+ }
42
+
43
+ .slide-in-from-bottom-4 {
44
+ animation-name: slideInFromBottom;
45
+ }
46
+
47
+ .fade-in {
48
+ animation: fadeIn 300ms ease-out;
49
+ }
50
+
51
+ @keyframes fadeIn {
52
+ from {
53
+ opacity: 0;
54
+ }
55
+ to {
56
+ opacity: 1;
57
+ }
58
+ }
59
+
60
+ /* Smooth scrolling */
61
+ html {
62
+ scroll-behavior: smooth;
63
+ }
64
+
65
+ /* Better focus states */
66
+ *:focus {
67
+ outline: none;
68
+ }
69
+
70
+ *:focus-visible {
71
+ outline: 2px solid rgb(99, 102, 241);
72
+ outline-offset: 2px;
73
+ }
74
+
75
+ /* Message content styling */
76
+ .prose {
77
+ max-width: none;
78
+ }
79
+
80
+ .prose p {
81
+ margin-bottom: 0.5em;
82
+ }
83
+
84
+ .prose p:last-child {
85
+ margin-bottom: 0;
86
+ }
87
+
88
+ /* Gradient text animation (optional) */
89
+ @keyframes gradientShift {
90
+ 0%, 100% {
91
+ background-position: 0% 50%;
92
+ }
93
+ 50% {
94
+ background-position: 100% 50%;
95
+ }
96
+ }
97
+
98
+ .gradient-animate {
99
+ background-size: 200% 200%;
100
+ animation: gradientShift 3s ease infinite;
101
+ }
102
+
103
+ /* Selection color */
104
+ ::selection {
105
+ background-color: rgb(199, 210, 254);
106
+ color: rgb(55, 48, 163);
107
+ }
108
+
109
+ /* Loading pulse animation */
110
+ @keyframes pulse {
111
+ 0%, 100% {
112
+ opacity: 1;
113
+ }
114
+ 50% {
115
+ opacity: 0.5;
116
+ }
117
+ }
118
+
119
+ .animate-pulse {
120
+ animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
121
+ }
122
+
123
+ /* Bounce animation for typing indicator */
124
+ @keyframes bounce {
125
+ 0%, 100% {
126
+ transform: translateY(0);
127
+ }
128
+ 50% {
129
+ transform: translateY(-4px);
130
+ }
131
+ }
132
+
133
+ .animate-bounce {
134
+ animation: bounce 0.6s infinite;
135
+ }
index.html ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <!DOCTYPE html>
3
+ <html lang="en">
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Briefly AI - Professional Summarizer</title>
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <link rel="preconnect" href="https://fonts.googleapis.com">
10
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
12
+ <style>
13
+ body {
14
+ font-family: 'Inter', sans-serif;
15
+ background-color: #f9fafb;
16
+ }
17
+ </style>
18
+ <script type="importmap">
19
+ {
20
+ "imports": {
21
+ "react": "https://esm.sh/react@^19.2.4",
22
+ "react-dom/": "https://esm.sh/react-dom@^19.2.4/",
23
+ "react/": "https://esm.sh/react@^19.2.4/",
24
+ "@google/genai": "https://esm.sh/@google/genai@^1.38.0"
25
+ }
26
+ }
27
+ </script>
28
+ <link rel="stylesheet" href="/index.css">
29
+ </head>
30
+ <body>
31
+ <div id="root"></div>
32
+ <script type="module" src="/index.tsx"></script>
33
+ </body>
34
+ </html>
index.tsx ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import React from 'react';
3
+ import ReactDOM from 'react-dom/client';
4
+ import App from './App';
5
+
6
+ const rootElement = document.getElementById('root');
7
+ if (!rootElement) {
8
+ throw new Error("Could not find root element to mount to");
9
+ }
10
+
11
+ const root = ReactDOM.createRoot(rootElement);
12
+ root.render(
13
+ <React.StrictMode>
14
+ <App />
15
+ </React.StrictMode>
16
+ );
metadata.json ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+
2
+ {
3
+ "name": "Briefly AI",
4
+ "description": "A professional-grade text summarization tool that leverages Gemini AI to condense long articles into clear, concise summaries without losing key insights."
5
+ }
package-lock.json ADDED
@@ -0,0 +1,2719 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "briefly-ai",
3
+ "version": "0.0.0",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "briefly-ai",
9
+ "version": "0.0.0",
10
+ "dependencies": {
11
+ "@google/genai": "^1.38.0",
12
+ "@google/generative-ai": "^0.24.1",
13
+ "react": "^19.2.4",
14
+ "react-dom": "^19.2.4"
15
+ },
16
+ "devDependencies": {
17
+ "@types/node": "^22.14.0",
18
+ "@vitejs/plugin-react": "^5.0.0",
19
+ "typescript": "~5.8.2",
20
+ "vite": "^6.2.0"
21
+ }
22
+ },
23
+ "node_modules/@babel/code-frame": {
24
+ "version": "7.28.6",
25
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz",
26
+ "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==",
27
+ "dev": true,
28
+ "license": "MIT",
29
+ "dependencies": {
30
+ "@babel/helper-validator-identifier": "^7.28.5",
31
+ "js-tokens": "^4.0.0",
32
+ "picocolors": "^1.1.1"
33
+ },
34
+ "engines": {
35
+ "node": ">=6.9.0"
36
+ }
37
+ },
38
+ "node_modules/@babel/compat-data": {
39
+ "version": "7.28.6",
40
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.6.tgz",
41
+ "integrity": "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==",
42
+ "dev": true,
43
+ "license": "MIT",
44
+ "engines": {
45
+ "node": ">=6.9.0"
46
+ }
47
+ },
48
+ "node_modules/@babel/core": {
49
+ "version": "7.28.6",
50
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz",
51
+ "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==",
52
+ "dev": true,
53
+ "license": "MIT",
54
+ "dependencies": {
55
+ "@babel/code-frame": "^7.28.6",
56
+ "@babel/generator": "^7.28.6",
57
+ "@babel/helper-compilation-targets": "^7.28.6",
58
+ "@babel/helper-module-transforms": "^7.28.6",
59
+ "@babel/helpers": "^7.28.6",
60
+ "@babel/parser": "^7.28.6",
61
+ "@babel/template": "^7.28.6",
62
+ "@babel/traverse": "^7.28.6",
63
+ "@babel/types": "^7.28.6",
64
+ "@jridgewell/remapping": "^2.3.5",
65
+ "convert-source-map": "^2.0.0",
66
+ "debug": "^4.1.0",
67
+ "gensync": "^1.0.0-beta.2",
68
+ "json5": "^2.2.3",
69
+ "semver": "^6.3.1"
70
+ },
71
+ "engines": {
72
+ "node": ">=6.9.0"
73
+ },
74
+ "funding": {
75
+ "type": "opencollective",
76
+ "url": "https://opencollective.com/babel"
77
+ }
78
+ },
79
+ "node_modules/@babel/generator": {
80
+ "version": "7.28.6",
81
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.6.tgz",
82
+ "integrity": "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==",
83
+ "dev": true,
84
+ "license": "MIT",
85
+ "dependencies": {
86
+ "@babel/parser": "^7.28.6",
87
+ "@babel/types": "^7.28.6",
88
+ "@jridgewell/gen-mapping": "^0.3.12",
89
+ "@jridgewell/trace-mapping": "^0.3.28",
90
+ "jsesc": "^3.0.2"
91
+ },
92
+ "engines": {
93
+ "node": ">=6.9.0"
94
+ }
95
+ },
96
+ "node_modules/@babel/helper-compilation-targets": {
97
+ "version": "7.28.6",
98
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
99
+ "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
100
+ "dev": true,
101
+ "license": "MIT",
102
+ "dependencies": {
103
+ "@babel/compat-data": "^7.28.6",
104
+ "@babel/helper-validator-option": "^7.27.1",
105
+ "browserslist": "^4.24.0",
106
+ "lru-cache": "^5.1.1",
107
+ "semver": "^6.3.1"
108
+ },
109
+ "engines": {
110
+ "node": ">=6.9.0"
111
+ }
112
+ },
113
+ "node_modules/@babel/helper-globals": {
114
+ "version": "7.28.0",
115
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
116
+ "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
117
+ "dev": true,
118
+ "license": "MIT",
119
+ "engines": {
120
+ "node": ">=6.9.0"
121
+ }
122
+ },
123
+ "node_modules/@babel/helper-module-imports": {
124
+ "version": "7.28.6",
125
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
126
+ "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
127
+ "dev": true,
128
+ "license": "MIT",
129
+ "dependencies": {
130
+ "@babel/traverse": "^7.28.6",
131
+ "@babel/types": "^7.28.6"
132
+ },
133
+ "engines": {
134
+ "node": ">=6.9.0"
135
+ }
136
+ },
137
+ "node_modules/@babel/helper-module-transforms": {
138
+ "version": "7.28.6",
139
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
140
+ "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
141
+ "dev": true,
142
+ "license": "MIT",
143
+ "dependencies": {
144
+ "@babel/helper-module-imports": "^7.28.6",
145
+ "@babel/helper-validator-identifier": "^7.28.5",
146
+ "@babel/traverse": "^7.28.6"
147
+ },
148
+ "engines": {
149
+ "node": ">=6.9.0"
150
+ },
151
+ "peerDependencies": {
152
+ "@babel/core": "^7.0.0"
153
+ }
154
+ },
155
+ "node_modules/@babel/helper-plugin-utils": {
156
+ "version": "7.28.6",
157
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz",
158
+ "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==",
159
+ "dev": true,
160
+ "license": "MIT",
161
+ "engines": {
162
+ "node": ">=6.9.0"
163
+ }
164
+ },
165
+ "node_modules/@babel/helper-string-parser": {
166
+ "version": "7.27.1",
167
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
168
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
169
+ "dev": true,
170
+ "license": "MIT",
171
+ "engines": {
172
+ "node": ">=6.9.0"
173
+ }
174
+ },
175
+ "node_modules/@babel/helper-validator-identifier": {
176
+ "version": "7.28.5",
177
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
178
+ "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
179
+ "dev": true,
180
+ "license": "MIT",
181
+ "engines": {
182
+ "node": ">=6.9.0"
183
+ }
184
+ },
185
+ "node_modules/@babel/helper-validator-option": {
186
+ "version": "7.27.1",
187
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
188
+ "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
189
+ "dev": true,
190
+ "license": "MIT",
191
+ "engines": {
192
+ "node": ">=6.9.0"
193
+ }
194
+ },
195
+ "node_modules/@babel/helpers": {
196
+ "version": "7.28.6",
197
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz",
198
+ "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==",
199
+ "dev": true,
200
+ "license": "MIT",
201
+ "dependencies": {
202
+ "@babel/template": "^7.28.6",
203
+ "@babel/types": "^7.28.6"
204
+ },
205
+ "engines": {
206
+ "node": ">=6.9.0"
207
+ }
208
+ },
209
+ "node_modules/@babel/parser": {
210
+ "version": "7.28.6",
211
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz",
212
+ "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==",
213
+ "dev": true,
214
+ "license": "MIT",
215
+ "dependencies": {
216
+ "@babel/types": "^7.28.6"
217
+ },
218
+ "bin": {
219
+ "parser": "bin/babel-parser.js"
220
+ },
221
+ "engines": {
222
+ "node": ">=6.0.0"
223
+ }
224
+ },
225
+ "node_modules/@babel/plugin-transform-react-jsx-self": {
226
+ "version": "7.27.1",
227
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
228
+ "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
229
+ "dev": true,
230
+ "license": "MIT",
231
+ "dependencies": {
232
+ "@babel/helper-plugin-utils": "^7.27.1"
233
+ },
234
+ "engines": {
235
+ "node": ">=6.9.0"
236
+ },
237
+ "peerDependencies": {
238
+ "@babel/core": "^7.0.0-0"
239
+ }
240
+ },
241
+ "node_modules/@babel/plugin-transform-react-jsx-source": {
242
+ "version": "7.27.1",
243
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
244
+ "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
245
+ "dev": true,
246
+ "license": "MIT",
247
+ "dependencies": {
248
+ "@babel/helper-plugin-utils": "^7.27.1"
249
+ },
250
+ "engines": {
251
+ "node": ">=6.9.0"
252
+ },
253
+ "peerDependencies": {
254
+ "@babel/core": "^7.0.0-0"
255
+ }
256
+ },
257
+ "node_modules/@babel/template": {
258
+ "version": "7.28.6",
259
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
260
+ "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
261
+ "dev": true,
262
+ "license": "MIT",
263
+ "dependencies": {
264
+ "@babel/code-frame": "^7.28.6",
265
+ "@babel/parser": "^7.28.6",
266
+ "@babel/types": "^7.28.6"
267
+ },
268
+ "engines": {
269
+ "node": ">=6.9.0"
270
+ }
271
+ },
272
+ "node_modules/@babel/traverse": {
273
+ "version": "7.28.6",
274
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.6.tgz",
275
+ "integrity": "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==",
276
+ "dev": true,
277
+ "license": "MIT",
278
+ "dependencies": {
279
+ "@babel/code-frame": "^7.28.6",
280
+ "@babel/generator": "^7.28.6",
281
+ "@babel/helper-globals": "^7.28.0",
282
+ "@babel/parser": "^7.28.6",
283
+ "@babel/template": "^7.28.6",
284
+ "@babel/types": "^7.28.6",
285
+ "debug": "^4.3.1"
286
+ },
287
+ "engines": {
288
+ "node": ">=6.9.0"
289
+ }
290
+ },
291
+ "node_modules/@babel/types": {
292
+ "version": "7.28.6",
293
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz",
294
+ "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==",
295
+ "dev": true,
296
+ "license": "MIT",
297
+ "dependencies": {
298
+ "@babel/helper-string-parser": "^7.27.1",
299
+ "@babel/helper-validator-identifier": "^7.28.5"
300
+ },
301
+ "engines": {
302
+ "node": ">=6.9.0"
303
+ }
304
+ },
305
+ "node_modules/@esbuild/aix-ppc64": {
306
+ "version": "0.25.12",
307
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
308
+ "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
309
+ "cpu": [
310
+ "ppc64"
311
+ ],
312
+ "dev": true,
313
+ "license": "MIT",
314
+ "optional": true,
315
+ "os": [
316
+ "aix"
317
+ ],
318
+ "engines": {
319
+ "node": ">=18"
320
+ }
321
+ },
322
+ "node_modules/@esbuild/android-arm": {
323
+ "version": "0.25.12",
324
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
325
+ "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
326
+ "cpu": [
327
+ "arm"
328
+ ],
329
+ "dev": true,
330
+ "license": "MIT",
331
+ "optional": true,
332
+ "os": [
333
+ "android"
334
+ ],
335
+ "engines": {
336
+ "node": ">=18"
337
+ }
338
+ },
339
+ "node_modules/@esbuild/android-arm64": {
340
+ "version": "0.25.12",
341
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
342
+ "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
343
+ "cpu": [
344
+ "arm64"
345
+ ],
346
+ "dev": true,
347
+ "license": "MIT",
348
+ "optional": true,
349
+ "os": [
350
+ "android"
351
+ ],
352
+ "engines": {
353
+ "node": ">=18"
354
+ }
355
+ },
356
+ "node_modules/@esbuild/android-x64": {
357
+ "version": "0.25.12",
358
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
359
+ "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
360
+ "cpu": [
361
+ "x64"
362
+ ],
363
+ "dev": true,
364
+ "license": "MIT",
365
+ "optional": true,
366
+ "os": [
367
+ "android"
368
+ ],
369
+ "engines": {
370
+ "node": ">=18"
371
+ }
372
+ },
373
+ "node_modules/@esbuild/darwin-arm64": {
374
+ "version": "0.25.12",
375
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
376
+ "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
377
+ "cpu": [
378
+ "arm64"
379
+ ],
380
+ "dev": true,
381
+ "license": "MIT",
382
+ "optional": true,
383
+ "os": [
384
+ "darwin"
385
+ ],
386
+ "engines": {
387
+ "node": ">=18"
388
+ }
389
+ },
390
+ "node_modules/@esbuild/darwin-x64": {
391
+ "version": "0.25.12",
392
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
393
+ "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
394
+ "cpu": [
395
+ "x64"
396
+ ],
397
+ "dev": true,
398
+ "license": "MIT",
399
+ "optional": true,
400
+ "os": [
401
+ "darwin"
402
+ ],
403
+ "engines": {
404
+ "node": ">=18"
405
+ }
406
+ },
407
+ "node_modules/@esbuild/freebsd-arm64": {
408
+ "version": "0.25.12",
409
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
410
+ "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
411
+ "cpu": [
412
+ "arm64"
413
+ ],
414
+ "dev": true,
415
+ "license": "MIT",
416
+ "optional": true,
417
+ "os": [
418
+ "freebsd"
419
+ ],
420
+ "engines": {
421
+ "node": ">=18"
422
+ }
423
+ },
424
+ "node_modules/@esbuild/freebsd-x64": {
425
+ "version": "0.25.12",
426
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
427
+ "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
428
+ "cpu": [
429
+ "x64"
430
+ ],
431
+ "dev": true,
432
+ "license": "MIT",
433
+ "optional": true,
434
+ "os": [
435
+ "freebsd"
436
+ ],
437
+ "engines": {
438
+ "node": ">=18"
439
+ }
440
+ },
441
+ "node_modules/@esbuild/linux-arm": {
442
+ "version": "0.25.12",
443
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
444
+ "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
445
+ "cpu": [
446
+ "arm"
447
+ ],
448
+ "dev": true,
449
+ "license": "MIT",
450
+ "optional": true,
451
+ "os": [
452
+ "linux"
453
+ ],
454
+ "engines": {
455
+ "node": ">=18"
456
+ }
457
+ },
458
+ "node_modules/@esbuild/linux-arm64": {
459
+ "version": "0.25.12",
460
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
461
+ "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
462
+ "cpu": [
463
+ "arm64"
464
+ ],
465
+ "dev": true,
466
+ "license": "MIT",
467
+ "optional": true,
468
+ "os": [
469
+ "linux"
470
+ ],
471
+ "engines": {
472
+ "node": ">=18"
473
+ }
474
+ },
475
+ "node_modules/@esbuild/linux-ia32": {
476
+ "version": "0.25.12",
477
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
478
+ "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
479
+ "cpu": [
480
+ "ia32"
481
+ ],
482
+ "dev": true,
483
+ "license": "MIT",
484
+ "optional": true,
485
+ "os": [
486
+ "linux"
487
+ ],
488
+ "engines": {
489
+ "node": ">=18"
490
+ }
491
+ },
492
+ "node_modules/@esbuild/linux-loong64": {
493
+ "version": "0.25.12",
494
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
495
+ "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
496
+ "cpu": [
497
+ "loong64"
498
+ ],
499
+ "dev": true,
500
+ "license": "MIT",
501
+ "optional": true,
502
+ "os": [
503
+ "linux"
504
+ ],
505
+ "engines": {
506
+ "node": ">=18"
507
+ }
508
+ },
509
+ "node_modules/@esbuild/linux-mips64el": {
510
+ "version": "0.25.12",
511
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
512
+ "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
513
+ "cpu": [
514
+ "mips64el"
515
+ ],
516
+ "dev": true,
517
+ "license": "MIT",
518
+ "optional": true,
519
+ "os": [
520
+ "linux"
521
+ ],
522
+ "engines": {
523
+ "node": ">=18"
524
+ }
525
+ },
526
+ "node_modules/@esbuild/linux-ppc64": {
527
+ "version": "0.25.12",
528
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
529
+ "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
530
+ "cpu": [
531
+ "ppc64"
532
+ ],
533
+ "dev": true,
534
+ "license": "MIT",
535
+ "optional": true,
536
+ "os": [
537
+ "linux"
538
+ ],
539
+ "engines": {
540
+ "node": ">=18"
541
+ }
542
+ },
543
+ "node_modules/@esbuild/linux-riscv64": {
544
+ "version": "0.25.12",
545
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
546
+ "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
547
+ "cpu": [
548
+ "riscv64"
549
+ ],
550
+ "dev": true,
551
+ "license": "MIT",
552
+ "optional": true,
553
+ "os": [
554
+ "linux"
555
+ ],
556
+ "engines": {
557
+ "node": ">=18"
558
+ }
559
+ },
560
+ "node_modules/@esbuild/linux-s390x": {
561
+ "version": "0.25.12",
562
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
563
+ "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
564
+ "cpu": [
565
+ "s390x"
566
+ ],
567
+ "dev": true,
568
+ "license": "MIT",
569
+ "optional": true,
570
+ "os": [
571
+ "linux"
572
+ ],
573
+ "engines": {
574
+ "node": ">=18"
575
+ }
576
+ },
577
+ "node_modules/@esbuild/linux-x64": {
578
+ "version": "0.25.12",
579
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
580
+ "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
581
+ "cpu": [
582
+ "x64"
583
+ ],
584
+ "dev": true,
585
+ "license": "MIT",
586
+ "optional": true,
587
+ "os": [
588
+ "linux"
589
+ ],
590
+ "engines": {
591
+ "node": ">=18"
592
+ }
593
+ },
594
+ "node_modules/@esbuild/netbsd-arm64": {
595
+ "version": "0.25.12",
596
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
597
+ "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
598
+ "cpu": [
599
+ "arm64"
600
+ ],
601
+ "dev": true,
602
+ "license": "MIT",
603
+ "optional": true,
604
+ "os": [
605
+ "netbsd"
606
+ ],
607
+ "engines": {
608
+ "node": ">=18"
609
+ }
610
+ },
611
+ "node_modules/@esbuild/netbsd-x64": {
612
+ "version": "0.25.12",
613
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
614
+ "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
615
+ "cpu": [
616
+ "x64"
617
+ ],
618
+ "dev": true,
619
+ "license": "MIT",
620
+ "optional": true,
621
+ "os": [
622
+ "netbsd"
623
+ ],
624
+ "engines": {
625
+ "node": ">=18"
626
+ }
627
+ },
628
+ "node_modules/@esbuild/openbsd-arm64": {
629
+ "version": "0.25.12",
630
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
631
+ "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
632
+ "cpu": [
633
+ "arm64"
634
+ ],
635
+ "dev": true,
636
+ "license": "MIT",
637
+ "optional": true,
638
+ "os": [
639
+ "openbsd"
640
+ ],
641
+ "engines": {
642
+ "node": ">=18"
643
+ }
644
+ },
645
+ "node_modules/@esbuild/openbsd-x64": {
646
+ "version": "0.25.12",
647
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
648
+ "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
649
+ "cpu": [
650
+ "x64"
651
+ ],
652
+ "dev": true,
653
+ "license": "MIT",
654
+ "optional": true,
655
+ "os": [
656
+ "openbsd"
657
+ ],
658
+ "engines": {
659
+ "node": ">=18"
660
+ }
661
+ },
662
+ "node_modules/@esbuild/openharmony-arm64": {
663
+ "version": "0.25.12",
664
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
665
+ "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
666
+ "cpu": [
667
+ "arm64"
668
+ ],
669
+ "dev": true,
670
+ "license": "MIT",
671
+ "optional": true,
672
+ "os": [
673
+ "openharmony"
674
+ ],
675
+ "engines": {
676
+ "node": ">=18"
677
+ }
678
+ },
679
+ "node_modules/@esbuild/sunos-x64": {
680
+ "version": "0.25.12",
681
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
682
+ "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
683
+ "cpu": [
684
+ "x64"
685
+ ],
686
+ "dev": true,
687
+ "license": "MIT",
688
+ "optional": true,
689
+ "os": [
690
+ "sunos"
691
+ ],
692
+ "engines": {
693
+ "node": ">=18"
694
+ }
695
+ },
696
+ "node_modules/@esbuild/win32-arm64": {
697
+ "version": "0.25.12",
698
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
699
+ "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
700
+ "cpu": [
701
+ "arm64"
702
+ ],
703
+ "dev": true,
704
+ "license": "MIT",
705
+ "optional": true,
706
+ "os": [
707
+ "win32"
708
+ ],
709
+ "engines": {
710
+ "node": ">=18"
711
+ }
712
+ },
713
+ "node_modules/@esbuild/win32-ia32": {
714
+ "version": "0.25.12",
715
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
716
+ "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
717
+ "cpu": [
718
+ "ia32"
719
+ ],
720
+ "dev": true,
721
+ "license": "MIT",
722
+ "optional": true,
723
+ "os": [
724
+ "win32"
725
+ ],
726
+ "engines": {
727
+ "node": ">=18"
728
+ }
729
+ },
730
+ "node_modules/@esbuild/win32-x64": {
731
+ "version": "0.25.12",
732
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
733
+ "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
734
+ "cpu": [
735
+ "x64"
736
+ ],
737
+ "dev": true,
738
+ "license": "MIT",
739
+ "optional": true,
740
+ "os": [
741
+ "win32"
742
+ ],
743
+ "engines": {
744
+ "node": ">=18"
745
+ }
746
+ },
747
+ "node_modules/@google/genai": {
748
+ "version": "1.38.0",
749
+ "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.38.0.tgz",
750
+ "integrity": "sha512-V/4CQVQGovvGHuS73lwJwHKR9x33kCij3zz/ReEQ4A7RJaV0U7m4k1mvYhFk55cGZdF5JLKu2S9BTaFuEs5xTA==",
751
+ "license": "Apache-2.0",
752
+ "dependencies": {
753
+ "google-auth-library": "^10.3.0",
754
+ "protobufjs": "^7.5.4",
755
+ "ws": "^8.18.0"
756
+ },
757
+ "engines": {
758
+ "node": ">=20.0.0"
759
+ },
760
+ "peerDependencies": {
761
+ "@modelcontextprotocol/sdk": "^1.25.2"
762
+ },
763
+ "peerDependenciesMeta": {
764
+ "@modelcontextprotocol/sdk": {
765
+ "optional": true
766
+ }
767
+ }
768
+ },
769
+ "node_modules/@google/generative-ai": {
770
+ "version": "0.24.1",
771
+ "resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.24.1.tgz",
772
+ "integrity": "sha512-MqO+MLfM6kjxcKoy0p1wRzG3b4ZZXtPI+z2IE26UogS2Cm/XHO+7gGRBh6gcJsOiIVoH93UwKvW4HdgiOZCy9Q==",
773
+ "license": "Apache-2.0",
774
+ "engines": {
775
+ "node": ">=18.0.0"
776
+ }
777
+ },
778
+ "node_modules/@isaacs/cliui": {
779
+ "version": "8.0.2",
780
+ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
781
+ "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
782
+ "license": "ISC",
783
+ "dependencies": {
784
+ "string-width": "^5.1.2",
785
+ "string-width-cjs": "npm:string-width@^4.2.0",
786
+ "strip-ansi": "^7.0.1",
787
+ "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
788
+ "wrap-ansi": "^8.1.0",
789
+ "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
790
+ },
791
+ "engines": {
792
+ "node": ">=12"
793
+ }
794
+ },
795
+ "node_modules/@jridgewell/gen-mapping": {
796
+ "version": "0.3.13",
797
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
798
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
799
+ "dev": true,
800
+ "license": "MIT",
801
+ "dependencies": {
802
+ "@jridgewell/sourcemap-codec": "^1.5.0",
803
+ "@jridgewell/trace-mapping": "^0.3.24"
804
+ }
805
+ },
806
+ "node_modules/@jridgewell/remapping": {
807
+ "version": "2.3.5",
808
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
809
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
810
+ "dev": true,
811
+ "license": "MIT",
812
+ "dependencies": {
813
+ "@jridgewell/gen-mapping": "^0.3.5",
814
+ "@jridgewell/trace-mapping": "^0.3.24"
815
+ }
816
+ },
817
+ "node_modules/@jridgewell/resolve-uri": {
818
+ "version": "3.1.2",
819
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
820
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
821
+ "dev": true,
822
+ "license": "MIT",
823
+ "engines": {
824
+ "node": ">=6.0.0"
825
+ }
826
+ },
827
+ "node_modules/@jridgewell/sourcemap-codec": {
828
+ "version": "1.5.5",
829
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
830
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
831
+ "dev": true,
832
+ "license": "MIT"
833
+ },
834
+ "node_modules/@jridgewell/trace-mapping": {
835
+ "version": "0.3.31",
836
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
837
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
838
+ "dev": true,
839
+ "license": "MIT",
840
+ "dependencies": {
841
+ "@jridgewell/resolve-uri": "^3.1.0",
842
+ "@jridgewell/sourcemap-codec": "^1.4.14"
843
+ }
844
+ },
845
+ "node_modules/@pkgjs/parseargs": {
846
+ "version": "0.11.0",
847
+ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
848
+ "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
849
+ "license": "MIT",
850
+ "optional": true,
851
+ "engines": {
852
+ "node": ">=14"
853
+ }
854
+ },
855
+ "node_modules/@protobufjs/aspromise": {
856
+ "version": "1.1.2",
857
+ "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
858
+ "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
859
+ "license": "BSD-3-Clause"
860
+ },
861
+ "node_modules/@protobufjs/base64": {
862
+ "version": "1.1.2",
863
+ "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
864
+ "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
865
+ "license": "BSD-3-Clause"
866
+ },
867
+ "node_modules/@protobufjs/codegen": {
868
+ "version": "2.0.4",
869
+ "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
870
+ "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==",
871
+ "license": "BSD-3-Clause"
872
+ },
873
+ "node_modules/@protobufjs/eventemitter": {
874
+ "version": "1.1.0",
875
+ "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
876
+ "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==",
877
+ "license": "BSD-3-Clause"
878
+ },
879
+ "node_modules/@protobufjs/fetch": {
880
+ "version": "1.1.0",
881
+ "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
882
+ "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
883
+ "license": "BSD-3-Clause",
884
+ "dependencies": {
885
+ "@protobufjs/aspromise": "^1.1.1",
886
+ "@protobufjs/inquire": "^1.1.0"
887
+ }
888
+ },
889
+ "node_modules/@protobufjs/float": {
890
+ "version": "1.0.2",
891
+ "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
892
+ "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
893
+ "license": "BSD-3-Clause"
894
+ },
895
+ "node_modules/@protobufjs/inquire": {
896
+ "version": "1.1.0",
897
+ "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
898
+ "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==",
899
+ "license": "BSD-3-Clause"
900
+ },
901
+ "node_modules/@protobufjs/path": {
902
+ "version": "1.1.2",
903
+ "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
904
+ "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
905
+ "license": "BSD-3-Clause"
906
+ },
907
+ "node_modules/@protobufjs/pool": {
908
+ "version": "1.1.0",
909
+ "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
910
+ "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
911
+ "license": "BSD-3-Clause"
912
+ },
913
+ "node_modules/@protobufjs/utf8": {
914
+ "version": "1.1.0",
915
+ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
916
+ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
917
+ "license": "BSD-3-Clause"
918
+ },
919
+ "node_modules/@rolldown/pluginutils": {
920
+ "version": "1.0.0-beta.53",
921
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.53.tgz",
922
+ "integrity": "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==",
923
+ "dev": true,
924
+ "license": "MIT"
925
+ },
926
+ "node_modules/@rollup/rollup-android-arm-eabi": {
927
+ "version": "4.56.0",
928
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.56.0.tgz",
929
+ "integrity": "sha512-LNKIPA5k8PF1+jAFomGe3qN3bbIgJe/IlpDBwuVjrDKrJhVWywgnJvflMt/zkbVNLFtF1+94SljYQS6e99klnw==",
930
+ "cpu": [
931
+ "arm"
932
+ ],
933
+ "dev": true,
934
+ "license": "MIT",
935
+ "optional": true,
936
+ "os": [
937
+ "android"
938
+ ]
939
+ },
940
+ "node_modules/@rollup/rollup-android-arm64": {
941
+ "version": "4.56.0",
942
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.56.0.tgz",
943
+ "integrity": "sha512-lfbVUbelYqXlYiU/HApNMJzT1E87UPGvzveGg2h0ktUNlOCxKlWuJ9jtfvs1sKHdwU4fzY7Pl8sAl49/XaEk6Q==",
944
+ "cpu": [
945
+ "arm64"
946
+ ],
947
+ "dev": true,
948
+ "license": "MIT",
949
+ "optional": true,
950
+ "os": [
951
+ "android"
952
+ ]
953
+ },
954
+ "node_modules/@rollup/rollup-darwin-arm64": {
955
+ "version": "4.56.0",
956
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.56.0.tgz",
957
+ "integrity": "sha512-EgxD1ocWfhoD6xSOeEEwyE7tDvwTgZc8Bss7wCWe+uc7wO8G34HHCUH+Q6cHqJubxIAnQzAsyUsClt0yFLu06w==",
958
+ "cpu": [
959
+ "arm64"
960
+ ],
961
+ "dev": true,
962
+ "license": "MIT",
963
+ "optional": true,
964
+ "os": [
965
+ "darwin"
966
+ ]
967
+ },
968
+ "node_modules/@rollup/rollup-darwin-x64": {
969
+ "version": "4.56.0",
970
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.56.0.tgz",
971
+ "integrity": "sha512-1vXe1vcMOssb/hOF8iv52A7feWW2xnu+c8BV4t1F//m9QVLTfNVpEdja5ia762j/UEJe2Z1jAmEqZAK42tVW3g==",
972
+ "cpu": [
973
+ "x64"
974
+ ],
975
+ "dev": true,
976
+ "license": "MIT",
977
+ "optional": true,
978
+ "os": [
979
+ "darwin"
980
+ ]
981
+ },
982
+ "node_modules/@rollup/rollup-freebsd-arm64": {
983
+ "version": "4.56.0",
984
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.56.0.tgz",
985
+ "integrity": "sha512-bof7fbIlvqsyv/DtaXSck4VYQ9lPtoWNFCB/JY4snlFuJREXfZnm+Ej6yaCHfQvofJDXLDMTVxWscVSuQvVWUQ==",
986
+ "cpu": [
987
+ "arm64"
988
+ ],
989
+ "dev": true,
990
+ "license": "MIT",
991
+ "optional": true,
992
+ "os": [
993
+ "freebsd"
994
+ ]
995
+ },
996
+ "node_modules/@rollup/rollup-freebsd-x64": {
997
+ "version": "4.56.0",
998
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.56.0.tgz",
999
+ "integrity": "sha512-KNa6lYHloW+7lTEkYGa37fpvPq+NKG/EHKM8+G/g9WDU7ls4sMqbVRV78J6LdNuVaeeK5WB9/9VAFbKxcbXKYg==",
1000
+ "cpu": [
1001
+ "x64"
1002
+ ],
1003
+ "dev": true,
1004
+ "license": "MIT",
1005
+ "optional": true,
1006
+ "os": [
1007
+ "freebsd"
1008
+ ]
1009
+ },
1010
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
1011
+ "version": "4.56.0",
1012
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.56.0.tgz",
1013
+ "integrity": "sha512-E8jKK87uOvLrrLN28jnAAAChNq5LeCd2mGgZF+fGF5D507WlG/Noct3lP/QzQ6MrqJ5BCKNwI9ipADB6jyiq2A==",
1014
+ "cpu": [
1015
+ "arm"
1016
+ ],
1017
+ "dev": true,
1018
+ "license": "MIT",
1019
+ "optional": true,
1020
+ "os": [
1021
+ "linux"
1022
+ ]
1023
+ },
1024
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
1025
+ "version": "4.56.0",
1026
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.56.0.tgz",
1027
+ "integrity": "sha512-jQosa5FMYF5Z6prEpTCCmzCXz6eKr/tCBssSmQGEeozA9tkRUty/5Vx06ibaOP9RCrW1Pvb8yp3gvZhHwTDsJw==",
1028
+ "cpu": [
1029
+ "arm"
1030
+ ],
1031
+ "dev": true,
1032
+ "license": "MIT",
1033
+ "optional": true,
1034
+ "os": [
1035
+ "linux"
1036
+ ]
1037
+ },
1038
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
1039
+ "version": "4.56.0",
1040
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.56.0.tgz",
1041
+ "integrity": "sha512-uQVoKkrC1KGEV6udrdVahASIsaF8h7iLG0U0W+Xn14ucFwi6uS539PsAr24IEF9/FoDtzMeeJXJIBo5RkbNWvQ==",
1042
+ "cpu": [
1043
+ "arm64"
1044
+ ],
1045
+ "dev": true,
1046
+ "license": "MIT",
1047
+ "optional": true,
1048
+ "os": [
1049
+ "linux"
1050
+ ]
1051
+ },
1052
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
1053
+ "version": "4.56.0",
1054
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.56.0.tgz",
1055
+ "integrity": "sha512-vLZ1yJKLxhQLFKTs42RwTwa6zkGln+bnXc8ueFGMYmBTLfNu58sl5/eXyxRa2RarTkJbXl8TKPgfS6V5ijNqEA==",
1056
+ "cpu": [
1057
+ "arm64"
1058
+ ],
1059
+ "dev": true,
1060
+ "license": "MIT",
1061
+ "optional": true,
1062
+ "os": [
1063
+ "linux"
1064
+ ]
1065
+ },
1066
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
1067
+ "version": "4.56.0",
1068
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.56.0.tgz",
1069
+ "integrity": "sha512-FWfHOCub564kSE3xJQLLIC/hbKqHSVxy8vY75/YHHzWvbJL7aYJkdgwD/xGfUlL5UV2SB7otapLrcCj2xnF1dg==",
1070
+ "cpu": [
1071
+ "loong64"
1072
+ ],
1073
+ "dev": true,
1074
+ "license": "MIT",
1075
+ "optional": true,
1076
+ "os": [
1077
+ "linux"
1078
+ ]
1079
+ },
1080
+ "node_modules/@rollup/rollup-linux-loong64-musl": {
1081
+ "version": "4.56.0",
1082
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.56.0.tgz",
1083
+ "integrity": "sha512-z1EkujxIh7nbrKL1lmIpqFTc/sr0u8Uk0zK/qIEFldbt6EDKWFk/pxFq3gYj4Bjn3aa9eEhYRlL3H8ZbPT1xvA==",
1084
+ "cpu": [
1085
+ "loong64"
1086
+ ],
1087
+ "dev": true,
1088
+ "license": "MIT",
1089
+ "optional": true,
1090
+ "os": [
1091
+ "linux"
1092
+ ]
1093
+ },
1094
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
1095
+ "version": "4.56.0",
1096
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.56.0.tgz",
1097
+ "integrity": "sha512-iNFTluqgdoQC7AIE8Q34R3AuPrJGJirj5wMUErxj22deOcY7XwZRaqYmB6ZKFHoVGqRcRd0mqO+845jAibKCkw==",
1098
+ "cpu": [
1099
+ "ppc64"
1100
+ ],
1101
+ "dev": true,
1102
+ "license": "MIT",
1103
+ "optional": true,
1104
+ "os": [
1105
+ "linux"
1106
+ ]
1107
+ },
1108
+ "node_modules/@rollup/rollup-linux-ppc64-musl": {
1109
+ "version": "4.56.0",
1110
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.56.0.tgz",
1111
+ "integrity": "sha512-MtMeFVlD2LIKjp2sE2xM2slq3Zxf9zwVuw0jemsxvh1QOpHSsSzfNOTH9uYW9i1MXFxUSMmLpeVeUzoNOKBaWg==",
1112
+ "cpu": [
1113
+ "ppc64"
1114
+ ],
1115
+ "dev": true,
1116
+ "license": "MIT",
1117
+ "optional": true,
1118
+ "os": [
1119
+ "linux"
1120
+ ]
1121
+ },
1122
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
1123
+ "version": "4.56.0",
1124
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.56.0.tgz",
1125
+ "integrity": "sha512-in+v6wiHdzzVhYKXIk5U74dEZHdKN9KH0Q4ANHOTvyXPG41bajYRsy7a8TPKbYPl34hU7PP7hMVHRvv/5aCSew==",
1126
+ "cpu": [
1127
+ "riscv64"
1128
+ ],
1129
+ "dev": true,
1130
+ "license": "MIT",
1131
+ "optional": true,
1132
+ "os": [
1133
+ "linux"
1134
+ ]
1135
+ },
1136
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
1137
+ "version": "4.56.0",
1138
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.56.0.tgz",
1139
+ "integrity": "sha512-yni2raKHB8m9NQpI9fPVwN754mn6dHQSbDTwxdr9SE0ks38DTjLMMBjrwvB5+mXrX+C0npX0CVeCUcvvvD8CNQ==",
1140
+ "cpu": [
1141
+ "riscv64"
1142
+ ],
1143
+ "dev": true,
1144
+ "license": "MIT",
1145
+ "optional": true,
1146
+ "os": [
1147
+ "linux"
1148
+ ]
1149
+ },
1150
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
1151
+ "version": "4.56.0",
1152
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.56.0.tgz",
1153
+ "integrity": "sha512-zhLLJx9nQPu7wezbxt2ut+CI4YlXi68ndEve16tPc/iwoylWS9B3FxpLS2PkmfYgDQtosah07Mj9E0khc3Y+vQ==",
1154
+ "cpu": [
1155
+ "s390x"
1156
+ ],
1157
+ "dev": true,
1158
+ "license": "MIT",
1159
+ "optional": true,
1160
+ "os": [
1161
+ "linux"
1162
+ ]
1163
+ },
1164
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
1165
+ "version": "4.56.0",
1166
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.56.0.tgz",
1167
+ "integrity": "sha512-MVC6UDp16ZSH7x4rtuJPAEoE1RwS8N4oK9DLHy3FTEdFoUTCFVzMfJl/BVJ330C+hx8FfprA5Wqx4FhZXkj2Kw==",
1168
+ "cpu": [
1169
+ "x64"
1170
+ ],
1171
+ "dev": true,
1172
+ "license": "MIT",
1173
+ "optional": true,
1174
+ "os": [
1175
+ "linux"
1176
+ ]
1177
+ },
1178
+ "node_modules/@rollup/rollup-linux-x64-musl": {
1179
+ "version": "4.56.0",
1180
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.56.0.tgz",
1181
+ "integrity": "sha512-ZhGH1eA4Qv0lxaV00azCIS1ChedK0V32952Md3FtnxSqZTBTd6tgil4nZT5cU8B+SIw3PFYkvyR4FKo2oyZIHA==",
1182
+ "cpu": [
1183
+ "x64"
1184
+ ],
1185
+ "dev": true,
1186
+ "license": "MIT",
1187
+ "optional": true,
1188
+ "os": [
1189
+ "linux"
1190
+ ]
1191
+ },
1192
+ "node_modules/@rollup/rollup-openbsd-x64": {
1193
+ "version": "4.56.0",
1194
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.56.0.tgz",
1195
+ "integrity": "sha512-O16XcmyDeFI9879pEcmtWvD/2nyxR9mF7Gs44lf1vGGx8Vg2DRNx11aVXBEqOQhWb92WN4z7fW/q4+2NYzCbBA==",
1196
+ "cpu": [
1197
+ "x64"
1198
+ ],
1199
+ "dev": true,
1200
+ "license": "MIT",
1201
+ "optional": true,
1202
+ "os": [
1203
+ "openbsd"
1204
+ ]
1205
+ },
1206
+ "node_modules/@rollup/rollup-openharmony-arm64": {
1207
+ "version": "4.56.0",
1208
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.56.0.tgz",
1209
+ "integrity": "sha512-LhN/Reh+7F3RCgQIRbgw8ZMwUwyqJM+8pXNT6IIJAqm2IdKkzpCh/V9EdgOMBKuebIrzswqy4ATlrDgiOwbRcQ==",
1210
+ "cpu": [
1211
+ "arm64"
1212
+ ],
1213
+ "dev": true,
1214
+ "license": "MIT",
1215
+ "optional": true,
1216
+ "os": [
1217
+ "openharmony"
1218
+ ]
1219
+ },
1220
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
1221
+ "version": "4.56.0",
1222
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.56.0.tgz",
1223
+ "integrity": "sha512-kbFsOObXp3LBULg1d3JIUQMa9Kv4UitDmpS+k0tinPBz3watcUiV2/LUDMMucA6pZO3WGE27P7DsfaN54l9ing==",
1224
+ "cpu": [
1225
+ "arm64"
1226
+ ],
1227
+ "dev": true,
1228
+ "license": "MIT",
1229
+ "optional": true,
1230
+ "os": [
1231
+ "win32"
1232
+ ]
1233
+ },
1234
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
1235
+ "version": "4.56.0",
1236
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.56.0.tgz",
1237
+ "integrity": "sha512-vSSgny54D6P4vf2izbtFm/TcWYedw7f8eBrOiGGecyHyQB9q4Kqentjaj8hToe+995nob/Wv48pDqL5a62EWtg==",
1238
+ "cpu": [
1239
+ "ia32"
1240
+ ],
1241
+ "dev": true,
1242
+ "license": "MIT",
1243
+ "optional": true,
1244
+ "os": [
1245
+ "win32"
1246
+ ]
1247
+ },
1248
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
1249
+ "version": "4.56.0",
1250
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.56.0.tgz",
1251
+ "integrity": "sha512-FeCnkPCTHQJFbiGG49KjV5YGW/8b9rrXAM2Mz2kiIoktq2qsJxRD5giEMEOD2lPdgs72upzefaUvS+nc8E3UzQ==",
1252
+ "cpu": [
1253
+ "x64"
1254
+ ],
1255
+ "dev": true,
1256
+ "license": "MIT",
1257
+ "optional": true,
1258
+ "os": [
1259
+ "win32"
1260
+ ]
1261
+ },
1262
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
1263
+ "version": "4.56.0",
1264
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.56.0.tgz",
1265
+ "integrity": "sha512-H8AE9Ur/t0+1VXujj90w0HrSOuv0Nq9r1vSZF2t5km20NTfosQsGGUXDaKdQZzwuLts7IyL1fYT4hM95TI9c4g==",
1266
+ "cpu": [
1267
+ "x64"
1268
+ ],
1269
+ "dev": true,
1270
+ "license": "MIT",
1271
+ "optional": true,
1272
+ "os": [
1273
+ "win32"
1274
+ ]
1275
+ },
1276
+ "node_modules/@types/babel__core": {
1277
+ "version": "7.20.5",
1278
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
1279
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
1280
+ "dev": true,
1281
+ "license": "MIT",
1282
+ "dependencies": {
1283
+ "@babel/parser": "^7.20.7",
1284
+ "@babel/types": "^7.20.7",
1285
+ "@types/babel__generator": "*",
1286
+ "@types/babel__template": "*",
1287
+ "@types/babel__traverse": "*"
1288
+ }
1289
+ },
1290
+ "node_modules/@types/babel__generator": {
1291
+ "version": "7.27.0",
1292
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
1293
+ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
1294
+ "dev": true,
1295
+ "license": "MIT",
1296
+ "dependencies": {
1297
+ "@babel/types": "^7.0.0"
1298
+ }
1299
+ },
1300
+ "node_modules/@types/babel__template": {
1301
+ "version": "7.4.4",
1302
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
1303
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
1304
+ "dev": true,
1305
+ "license": "MIT",
1306
+ "dependencies": {
1307
+ "@babel/parser": "^7.1.0",
1308
+ "@babel/types": "^7.0.0"
1309
+ }
1310
+ },
1311
+ "node_modules/@types/babel__traverse": {
1312
+ "version": "7.28.0",
1313
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
1314
+ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
1315
+ "dev": true,
1316
+ "license": "MIT",
1317
+ "dependencies": {
1318
+ "@babel/types": "^7.28.2"
1319
+ }
1320
+ },
1321
+ "node_modules/@types/estree": {
1322
+ "version": "1.0.8",
1323
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
1324
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
1325
+ "dev": true,
1326
+ "license": "MIT"
1327
+ },
1328
+ "node_modules/@types/node": {
1329
+ "version": "22.19.7",
1330
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.7.tgz",
1331
+ "integrity": "sha512-MciR4AKGHWl7xwxkBa6xUGxQJ4VBOmPTF7sL+iGzuahOFaO0jHCsuEfS80pan1ef4gWId1oWOweIhrDEYLuaOw==",
1332
+ "license": "MIT",
1333
+ "dependencies": {
1334
+ "undici-types": "~6.21.0"
1335
+ }
1336
+ },
1337
+ "node_modules/@vitejs/plugin-react": {
1338
+ "version": "5.1.2",
1339
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.2.tgz",
1340
+ "integrity": "sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ==",
1341
+ "dev": true,
1342
+ "license": "MIT",
1343
+ "dependencies": {
1344
+ "@babel/core": "^7.28.5",
1345
+ "@babel/plugin-transform-react-jsx-self": "^7.27.1",
1346
+ "@babel/plugin-transform-react-jsx-source": "^7.27.1",
1347
+ "@rolldown/pluginutils": "1.0.0-beta.53",
1348
+ "@types/babel__core": "^7.20.5",
1349
+ "react-refresh": "^0.18.0"
1350
+ },
1351
+ "engines": {
1352
+ "node": "^20.19.0 || >=22.12.0"
1353
+ },
1354
+ "peerDependencies": {
1355
+ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
1356
+ }
1357
+ },
1358
+ "node_modules/agent-base": {
1359
+ "version": "7.1.4",
1360
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
1361
+ "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
1362
+ "license": "MIT",
1363
+ "engines": {
1364
+ "node": ">= 14"
1365
+ }
1366
+ },
1367
+ "node_modules/ansi-regex": {
1368
+ "version": "6.2.2",
1369
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
1370
+ "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
1371
+ "license": "MIT",
1372
+ "engines": {
1373
+ "node": ">=12"
1374
+ },
1375
+ "funding": {
1376
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
1377
+ }
1378
+ },
1379
+ "node_modules/ansi-styles": {
1380
+ "version": "6.2.3",
1381
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
1382
+ "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
1383
+ "license": "MIT",
1384
+ "engines": {
1385
+ "node": ">=12"
1386
+ },
1387
+ "funding": {
1388
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
1389
+ }
1390
+ },
1391
+ "node_modules/balanced-match": {
1392
+ "version": "1.0.2",
1393
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
1394
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
1395
+ "license": "MIT"
1396
+ },
1397
+ "node_modules/base64-js": {
1398
+ "version": "1.5.1",
1399
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
1400
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
1401
+ "funding": [
1402
+ {
1403
+ "type": "github",
1404
+ "url": "https://github.com/sponsors/feross"
1405
+ },
1406
+ {
1407
+ "type": "patreon",
1408
+ "url": "https://www.patreon.com/feross"
1409
+ },
1410
+ {
1411
+ "type": "consulting",
1412
+ "url": "https://feross.org/support"
1413
+ }
1414
+ ],
1415
+ "license": "MIT"
1416
+ },
1417
+ "node_modules/baseline-browser-mapping": {
1418
+ "version": "2.9.18",
1419
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.18.tgz",
1420
+ "integrity": "sha512-e23vBV1ZLfjb9apvfPk4rHVu2ry6RIr2Wfs+O324okSidrX7pTAnEJPCh/O5BtRlr7QtZI7ktOP3vsqr7Z5XoA==",
1421
+ "dev": true,
1422
+ "license": "Apache-2.0",
1423
+ "bin": {
1424
+ "baseline-browser-mapping": "dist/cli.js"
1425
+ }
1426
+ },
1427
+ "node_modules/bignumber.js": {
1428
+ "version": "9.3.1",
1429
+ "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz",
1430
+ "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==",
1431
+ "license": "MIT",
1432
+ "engines": {
1433
+ "node": "*"
1434
+ }
1435
+ },
1436
+ "node_modules/brace-expansion": {
1437
+ "version": "2.0.2",
1438
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
1439
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
1440
+ "license": "MIT",
1441
+ "dependencies": {
1442
+ "balanced-match": "^1.0.0"
1443
+ }
1444
+ },
1445
+ "node_modules/browserslist": {
1446
+ "version": "4.28.1",
1447
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
1448
+ "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
1449
+ "dev": true,
1450
+ "funding": [
1451
+ {
1452
+ "type": "opencollective",
1453
+ "url": "https://opencollective.com/browserslist"
1454
+ },
1455
+ {
1456
+ "type": "tidelift",
1457
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
1458
+ },
1459
+ {
1460
+ "type": "github",
1461
+ "url": "https://github.com/sponsors/ai"
1462
+ }
1463
+ ],
1464
+ "license": "MIT",
1465
+ "dependencies": {
1466
+ "baseline-browser-mapping": "^2.9.0",
1467
+ "caniuse-lite": "^1.0.30001759",
1468
+ "electron-to-chromium": "^1.5.263",
1469
+ "node-releases": "^2.0.27",
1470
+ "update-browserslist-db": "^1.2.0"
1471
+ },
1472
+ "bin": {
1473
+ "browserslist": "cli.js"
1474
+ },
1475
+ "engines": {
1476
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
1477
+ }
1478
+ },
1479
+ "node_modules/buffer-equal-constant-time": {
1480
+ "version": "1.0.1",
1481
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
1482
+ "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
1483
+ "license": "BSD-3-Clause"
1484
+ },
1485
+ "node_modules/caniuse-lite": {
1486
+ "version": "1.0.30001766",
1487
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001766.tgz",
1488
+ "integrity": "sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==",
1489
+ "dev": true,
1490
+ "funding": [
1491
+ {
1492
+ "type": "opencollective",
1493
+ "url": "https://opencollective.com/browserslist"
1494
+ },
1495
+ {
1496
+ "type": "tidelift",
1497
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
1498
+ },
1499
+ {
1500
+ "type": "github",
1501
+ "url": "https://github.com/sponsors/ai"
1502
+ }
1503
+ ],
1504
+ "license": "CC-BY-4.0"
1505
+ },
1506
+ "node_modules/color-convert": {
1507
+ "version": "2.0.1",
1508
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
1509
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
1510
+ "license": "MIT",
1511
+ "dependencies": {
1512
+ "color-name": "~1.1.4"
1513
+ },
1514
+ "engines": {
1515
+ "node": ">=7.0.0"
1516
+ }
1517
+ },
1518
+ "node_modules/color-name": {
1519
+ "version": "1.1.4",
1520
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
1521
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
1522
+ "license": "MIT"
1523
+ },
1524
+ "node_modules/convert-source-map": {
1525
+ "version": "2.0.0",
1526
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
1527
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
1528
+ "dev": true,
1529
+ "license": "MIT"
1530
+ },
1531
+ "node_modules/cross-spawn": {
1532
+ "version": "7.0.6",
1533
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
1534
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
1535
+ "license": "MIT",
1536
+ "dependencies": {
1537
+ "path-key": "^3.1.0",
1538
+ "shebang-command": "^2.0.0",
1539
+ "which": "^2.0.1"
1540
+ },
1541
+ "engines": {
1542
+ "node": ">= 8"
1543
+ }
1544
+ },
1545
+ "node_modules/data-uri-to-buffer": {
1546
+ "version": "4.0.1",
1547
+ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
1548
+ "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
1549
+ "license": "MIT",
1550
+ "engines": {
1551
+ "node": ">= 12"
1552
+ }
1553
+ },
1554
+ "node_modules/debug": {
1555
+ "version": "4.4.3",
1556
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
1557
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
1558
+ "license": "MIT",
1559
+ "dependencies": {
1560
+ "ms": "^2.1.3"
1561
+ },
1562
+ "engines": {
1563
+ "node": ">=6.0"
1564
+ },
1565
+ "peerDependenciesMeta": {
1566
+ "supports-color": {
1567
+ "optional": true
1568
+ }
1569
+ }
1570
+ },
1571
+ "node_modules/eastasianwidth": {
1572
+ "version": "0.2.0",
1573
+ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
1574
+ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
1575
+ "license": "MIT"
1576
+ },
1577
+ "node_modules/ecdsa-sig-formatter": {
1578
+ "version": "1.0.11",
1579
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
1580
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
1581
+ "license": "Apache-2.0",
1582
+ "dependencies": {
1583
+ "safe-buffer": "^5.0.1"
1584
+ }
1585
+ },
1586
+ "node_modules/electron-to-chromium": {
1587
+ "version": "1.5.279",
1588
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.279.tgz",
1589
+ "integrity": "sha512-0bblUU5UNdOt5G7XqGiJtpZMONma6WAfq9vsFmtn9x1+joAObr6x1chfqyxFSDCAFwFhCQDrqeAr6MYdpwJ9Hg==",
1590
+ "dev": true,
1591
+ "license": "ISC"
1592
+ },
1593
+ "node_modules/emoji-regex": {
1594
+ "version": "9.2.2",
1595
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
1596
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
1597
+ "license": "MIT"
1598
+ },
1599
+ "node_modules/esbuild": {
1600
+ "version": "0.25.12",
1601
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
1602
+ "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
1603
+ "dev": true,
1604
+ "hasInstallScript": true,
1605
+ "license": "MIT",
1606
+ "bin": {
1607
+ "esbuild": "bin/esbuild"
1608
+ },
1609
+ "engines": {
1610
+ "node": ">=18"
1611
+ },
1612
+ "optionalDependencies": {
1613
+ "@esbuild/aix-ppc64": "0.25.12",
1614
+ "@esbuild/android-arm": "0.25.12",
1615
+ "@esbuild/android-arm64": "0.25.12",
1616
+ "@esbuild/android-x64": "0.25.12",
1617
+ "@esbuild/darwin-arm64": "0.25.12",
1618
+ "@esbuild/darwin-x64": "0.25.12",
1619
+ "@esbuild/freebsd-arm64": "0.25.12",
1620
+ "@esbuild/freebsd-x64": "0.25.12",
1621
+ "@esbuild/linux-arm": "0.25.12",
1622
+ "@esbuild/linux-arm64": "0.25.12",
1623
+ "@esbuild/linux-ia32": "0.25.12",
1624
+ "@esbuild/linux-loong64": "0.25.12",
1625
+ "@esbuild/linux-mips64el": "0.25.12",
1626
+ "@esbuild/linux-ppc64": "0.25.12",
1627
+ "@esbuild/linux-riscv64": "0.25.12",
1628
+ "@esbuild/linux-s390x": "0.25.12",
1629
+ "@esbuild/linux-x64": "0.25.12",
1630
+ "@esbuild/netbsd-arm64": "0.25.12",
1631
+ "@esbuild/netbsd-x64": "0.25.12",
1632
+ "@esbuild/openbsd-arm64": "0.25.12",
1633
+ "@esbuild/openbsd-x64": "0.25.12",
1634
+ "@esbuild/openharmony-arm64": "0.25.12",
1635
+ "@esbuild/sunos-x64": "0.25.12",
1636
+ "@esbuild/win32-arm64": "0.25.12",
1637
+ "@esbuild/win32-ia32": "0.25.12",
1638
+ "@esbuild/win32-x64": "0.25.12"
1639
+ }
1640
+ },
1641
+ "node_modules/escalade": {
1642
+ "version": "3.2.0",
1643
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
1644
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
1645
+ "dev": true,
1646
+ "license": "MIT",
1647
+ "engines": {
1648
+ "node": ">=6"
1649
+ }
1650
+ },
1651
+ "node_modules/extend": {
1652
+ "version": "3.0.2",
1653
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
1654
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
1655
+ "license": "MIT"
1656
+ },
1657
+ "node_modules/fdir": {
1658
+ "version": "6.5.0",
1659
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
1660
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
1661
+ "dev": true,
1662
+ "license": "MIT",
1663
+ "engines": {
1664
+ "node": ">=12.0.0"
1665
+ },
1666
+ "peerDependencies": {
1667
+ "picomatch": "^3 || ^4"
1668
+ },
1669
+ "peerDependenciesMeta": {
1670
+ "picomatch": {
1671
+ "optional": true
1672
+ }
1673
+ }
1674
+ },
1675
+ "node_modules/fetch-blob": {
1676
+ "version": "3.2.0",
1677
+ "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
1678
+ "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
1679
+ "funding": [
1680
+ {
1681
+ "type": "github",
1682
+ "url": "https://github.com/sponsors/jimmywarting"
1683
+ },
1684
+ {
1685
+ "type": "paypal",
1686
+ "url": "https://paypal.me/jimmywarting"
1687
+ }
1688
+ ],
1689
+ "license": "MIT",
1690
+ "dependencies": {
1691
+ "node-domexception": "^1.0.0",
1692
+ "web-streams-polyfill": "^3.0.3"
1693
+ },
1694
+ "engines": {
1695
+ "node": "^12.20 || >= 14.13"
1696
+ }
1697
+ },
1698
+ "node_modules/foreground-child": {
1699
+ "version": "3.3.1",
1700
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
1701
+ "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
1702
+ "license": "ISC",
1703
+ "dependencies": {
1704
+ "cross-spawn": "^7.0.6",
1705
+ "signal-exit": "^4.0.1"
1706
+ },
1707
+ "engines": {
1708
+ "node": ">=14"
1709
+ },
1710
+ "funding": {
1711
+ "url": "https://github.com/sponsors/isaacs"
1712
+ }
1713
+ },
1714
+ "node_modules/formdata-polyfill": {
1715
+ "version": "4.0.10",
1716
+ "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
1717
+ "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
1718
+ "license": "MIT",
1719
+ "dependencies": {
1720
+ "fetch-blob": "^3.1.2"
1721
+ },
1722
+ "engines": {
1723
+ "node": ">=12.20.0"
1724
+ }
1725
+ },
1726
+ "node_modules/fsevents": {
1727
+ "version": "2.3.3",
1728
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
1729
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
1730
+ "dev": true,
1731
+ "hasInstallScript": true,
1732
+ "license": "MIT",
1733
+ "optional": true,
1734
+ "os": [
1735
+ "darwin"
1736
+ ],
1737
+ "engines": {
1738
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
1739
+ }
1740
+ },
1741
+ "node_modules/gaxios": {
1742
+ "version": "7.1.3",
1743
+ "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.3.tgz",
1744
+ "integrity": "sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==",
1745
+ "license": "Apache-2.0",
1746
+ "dependencies": {
1747
+ "extend": "^3.0.2",
1748
+ "https-proxy-agent": "^7.0.1",
1749
+ "node-fetch": "^3.3.2",
1750
+ "rimraf": "^5.0.1"
1751
+ },
1752
+ "engines": {
1753
+ "node": ">=18"
1754
+ }
1755
+ },
1756
+ "node_modules/gcp-metadata": {
1757
+ "version": "8.1.2",
1758
+ "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz",
1759
+ "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==",
1760
+ "license": "Apache-2.0",
1761
+ "dependencies": {
1762
+ "gaxios": "^7.0.0",
1763
+ "google-logging-utils": "^1.0.0",
1764
+ "json-bigint": "^1.0.0"
1765
+ },
1766
+ "engines": {
1767
+ "node": ">=18"
1768
+ }
1769
+ },
1770
+ "node_modules/gensync": {
1771
+ "version": "1.0.0-beta.2",
1772
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
1773
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
1774
+ "dev": true,
1775
+ "license": "MIT",
1776
+ "engines": {
1777
+ "node": ">=6.9.0"
1778
+ }
1779
+ },
1780
+ "node_modules/glob": {
1781
+ "version": "10.5.0",
1782
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
1783
+ "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
1784
+ "license": "ISC",
1785
+ "dependencies": {
1786
+ "foreground-child": "^3.1.0",
1787
+ "jackspeak": "^3.1.2",
1788
+ "minimatch": "^9.0.4",
1789
+ "minipass": "^7.1.2",
1790
+ "package-json-from-dist": "^1.0.0",
1791
+ "path-scurry": "^1.11.1"
1792
+ },
1793
+ "bin": {
1794
+ "glob": "dist/esm/bin.mjs"
1795
+ },
1796
+ "funding": {
1797
+ "url": "https://github.com/sponsors/isaacs"
1798
+ }
1799
+ },
1800
+ "node_modules/google-auth-library": {
1801
+ "version": "10.5.0",
1802
+ "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.5.0.tgz",
1803
+ "integrity": "sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w==",
1804
+ "license": "Apache-2.0",
1805
+ "dependencies": {
1806
+ "base64-js": "^1.3.0",
1807
+ "ecdsa-sig-formatter": "^1.0.11",
1808
+ "gaxios": "^7.0.0",
1809
+ "gcp-metadata": "^8.0.0",
1810
+ "google-logging-utils": "^1.0.0",
1811
+ "gtoken": "^8.0.0",
1812
+ "jws": "^4.0.0"
1813
+ },
1814
+ "engines": {
1815
+ "node": ">=18"
1816
+ }
1817
+ },
1818
+ "node_modules/google-logging-utils": {
1819
+ "version": "1.1.3",
1820
+ "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz",
1821
+ "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==",
1822
+ "license": "Apache-2.0",
1823
+ "engines": {
1824
+ "node": ">=14"
1825
+ }
1826
+ },
1827
+ "node_modules/gtoken": {
1828
+ "version": "8.0.0",
1829
+ "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-8.0.0.tgz",
1830
+ "integrity": "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==",
1831
+ "license": "MIT",
1832
+ "dependencies": {
1833
+ "gaxios": "^7.0.0",
1834
+ "jws": "^4.0.0"
1835
+ },
1836
+ "engines": {
1837
+ "node": ">=18"
1838
+ }
1839
+ },
1840
+ "node_modules/https-proxy-agent": {
1841
+ "version": "7.0.6",
1842
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
1843
+ "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
1844
+ "license": "MIT",
1845
+ "dependencies": {
1846
+ "agent-base": "^7.1.2",
1847
+ "debug": "4"
1848
+ },
1849
+ "engines": {
1850
+ "node": ">= 14"
1851
+ }
1852
+ },
1853
+ "node_modules/is-fullwidth-code-point": {
1854
+ "version": "3.0.0",
1855
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
1856
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
1857
+ "license": "MIT",
1858
+ "engines": {
1859
+ "node": ">=8"
1860
+ }
1861
+ },
1862
+ "node_modules/isexe": {
1863
+ "version": "2.0.0",
1864
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
1865
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
1866
+ "license": "ISC"
1867
+ },
1868
+ "node_modules/jackspeak": {
1869
+ "version": "3.4.3",
1870
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
1871
+ "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
1872
+ "license": "BlueOak-1.0.0",
1873
+ "dependencies": {
1874
+ "@isaacs/cliui": "^8.0.2"
1875
+ },
1876
+ "funding": {
1877
+ "url": "https://github.com/sponsors/isaacs"
1878
+ },
1879
+ "optionalDependencies": {
1880
+ "@pkgjs/parseargs": "^0.11.0"
1881
+ }
1882
+ },
1883
+ "node_modules/js-tokens": {
1884
+ "version": "4.0.0",
1885
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
1886
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
1887
+ "dev": true,
1888
+ "license": "MIT"
1889
+ },
1890
+ "node_modules/jsesc": {
1891
+ "version": "3.1.0",
1892
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
1893
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
1894
+ "dev": true,
1895
+ "license": "MIT",
1896
+ "bin": {
1897
+ "jsesc": "bin/jsesc"
1898
+ },
1899
+ "engines": {
1900
+ "node": ">=6"
1901
+ }
1902
+ },
1903
+ "node_modules/json-bigint": {
1904
+ "version": "1.0.0",
1905
+ "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
1906
+ "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
1907
+ "license": "MIT",
1908
+ "dependencies": {
1909
+ "bignumber.js": "^9.0.0"
1910
+ }
1911
+ },
1912
+ "node_modules/json5": {
1913
+ "version": "2.2.3",
1914
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
1915
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
1916
+ "dev": true,
1917
+ "license": "MIT",
1918
+ "bin": {
1919
+ "json5": "lib/cli.js"
1920
+ },
1921
+ "engines": {
1922
+ "node": ">=6"
1923
+ }
1924
+ },
1925
+ "node_modules/jwa": {
1926
+ "version": "2.0.1",
1927
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz",
1928
+ "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==",
1929
+ "license": "MIT",
1930
+ "dependencies": {
1931
+ "buffer-equal-constant-time": "^1.0.1",
1932
+ "ecdsa-sig-formatter": "1.0.11",
1933
+ "safe-buffer": "^5.0.1"
1934
+ }
1935
+ },
1936
+ "node_modules/jws": {
1937
+ "version": "4.0.1",
1938
+ "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz",
1939
+ "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==",
1940
+ "license": "MIT",
1941
+ "dependencies": {
1942
+ "jwa": "^2.0.1",
1943
+ "safe-buffer": "^5.0.1"
1944
+ }
1945
+ },
1946
+ "node_modules/long": {
1947
+ "version": "5.3.2",
1948
+ "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
1949
+ "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
1950
+ "license": "Apache-2.0"
1951
+ },
1952
+ "node_modules/lru-cache": {
1953
+ "version": "5.1.1",
1954
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
1955
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
1956
+ "dev": true,
1957
+ "license": "ISC",
1958
+ "dependencies": {
1959
+ "yallist": "^3.0.2"
1960
+ }
1961
+ },
1962
+ "node_modules/minimatch": {
1963
+ "version": "9.0.5",
1964
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
1965
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
1966
+ "license": "ISC",
1967
+ "dependencies": {
1968
+ "brace-expansion": "^2.0.1"
1969
+ },
1970
+ "engines": {
1971
+ "node": ">=16 || 14 >=14.17"
1972
+ },
1973
+ "funding": {
1974
+ "url": "https://github.com/sponsors/isaacs"
1975
+ }
1976
+ },
1977
+ "node_modules/minipass": {
1978
+ "version": "7.1.2",
1979
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
1980
+ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
1981
+ "license": "ISC",
1982
+ "engines": {
1983
+ "node": ">=16 || 14 >=14.17"
1984
+ }
1985
+ },
1986
+ "node_modules/ms": {
1987
+ "version": "2.1.3",
1988
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1989
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1990
+ "license": "MIT"
1991
+ },
1992
+ "node_modules/nanoid": {
1993
+ "version": "3.3.11",
1994
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
1995
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
1996
+ "dev": true,
1997
+ "funding": [
1998
+ {
1999
+ "type": "github",
2000
+ "url": "https://github.com/sponsors/ai"
2001
+ }
2002
+ ],
2003
+ "license": "MIT",
2004
+ "bin": {
2005
+ "nanoid": "bin/nanoid.cjs"
2006
+ },
2007
+ "engines": {
2008
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
2009
+ }
2010
+ },
2011
+ "node_modules/node-domexception": {
2012
+ "version": "1.0.0",
2013
+ "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
2014
+ "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
2015
+ "deprecated": "Use your platform's native DOMException instead",
2016
+ "funding": [
2017
+ {
2018
+ "type": "github",
2019
+ "url": "https://github.com/sponsors/jimmywarting"
2020
+ },
2021
+ {
2022
+ "type": "github",
2023
+ "url": "https://paypal.me/jimmywarting"
2024
+ }
2025
+ ],
2026
+ "license": "MIT",
2027
+ "engines": {
2028
+ "node": ">=10.5.0"
2029
+ }
2030
+ },
2031
+ "node_modules/node-fetch": {
2032
+ "version": "3.3.2",
2033
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
2034
+ "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
2035
+ "license": "MIT",
2036
+ "dependencies": {
2037
+ "data-uri-to-buffer": "^4.0.0",
2038
+ "fetch-blob": "^3.1.4",
2039
+ "formdata-polyfill": "^4.0.10"
2040
+ },
2041
+ "engines": {
2042
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
2043
+ },
2044
+ "funding": {
2045
+ "type": "opencollective",
2046
+ "url": "https://opencollective.com/node-fetch"
2047
+ }
2048
+ },
2049
+ "node_modules/node-releases": {
2050
+ "version": "2.0.27",
2051
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
2052
+ "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==",
2053
+ "dev": true,
2054
+ "license": "MIT"
2055
+ },
2056
+ "node_modules/package-json-from-dist": {
2057
+ "version": "1.0.1",
2058
+ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
2059
+ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
2060
+ "license": "BlueOak-1.0.0"
2061
+ },
2062
+ "node_modules/path-key": {
2063
+ "version": "3.1.1",
2064
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
2065
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
2066
+ "license": "MIT",
2067
+ "engines": {
2068
+ "node": ">=8"
2069
+ }
2070
+ },
2071
+ "node_modules/path-scurry": {
2072
+ "version": "1.11.1",
2073
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
2074
+ "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
2075
+ "license": "BlueOak-1.0.0",
2076
+ "dependencies": {
2077
+ "lru-cache": "^10.2.0",
2078
+ "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
2079
+ },
2080
+ "engines": {
2081
+ "node": ">=16 || 14 >=14.18"
2082
+ },
2083
+ "funding": {
2084
+ "url": "https://github.com/sponsors/isaacs"
2085
+ }
2086
+ },
2087
+ "node_modules/path-scurry/node_modules/lru-cache": {
2088
+ "version": "10.4.3",
2089
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
2090
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
2091
+ "license": "ISC"
2092
+ },
2093
+ "node_modules/picocolors": {
2094
+ "version": "1.1.1",
2095
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
2096
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
2097
+ "dev": true,
2098
+ "license": "ISC"
2099
+ },
2100
+ "node_modules/picomatch": {
2101
+ "version": "4.0.3",
2102
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
2103
+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
2104
+ "dev": true,
2105
+ "license": "MIT",
2106
+ "engines": {
2107
+ "node": ">=12"
2108
+ },
2109
+ "funding": {
2110
+ "url": "https://github.com/sponsors/jonschlinkert"
2111
+ }
2112
+ },
2113
+ "node_modules/postcss": {
2114
+ "version": "8.5.6",
2115
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
2116
+ "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
2117
+ "dev": true,
2118
+ "funding": [
2119
+ {
2120
+ "type": "opencollective",
2121
+ "url": "https://opencollective.com/postcss/"
2122
+ },
2123
+ {
2124
+ "type": "tidelift",
2125
+ "url": "https://tidelift.com/funding/github/npm/postcss"
2126
+ },
2127
+ {
2128
+ "type": "github",
2129
+ "url": "https://github.com/sponsors/ai"
2130
+ }
2131
+ ],
2132
+ "license": "MIT",
2133
+ "dependencies": {
2134
+ "nanoid": "^3.3.11",
2135
+ "picocolors": "^1.1.1",
2136
+ "source-map-js": "^1.2.1"
2137
+ },
2138
+ "engines": {
2139
+ "node": "^10 || ^12 || >=14"
2140
+ }
2141
+ },
2142
+ "node_modules/protobufjs": {
2143
+ "version": "7.5.4",
2144
+ "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz",
2145
+ "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==",
2146
+ "hasInstallScript": true,
2147
+ "license": "BSD-3-Clause",
2148
+ "dependencies": {
2149
+ "@protobufjs/aspromise": "^1.1.2",
2150
+ "@protobufjs/base64": "^1.1.2",
2151
+ "@protobufjs/codegen": "^2.0.4",
2152
+ "@protobufjs/eventemitter": "^1.1.0",
2153
+ "@protobufjs/fetch": "^1.1.0",
2154
+ "@protobufjs/float": "^1.0.2",
2155
+ "@protobufjs/inquire": "^1.1.0",
2156
+ "@protobufjs/path": "^1.1.2",
2157
+ "@protobufjs/pool": "^1.1.0",
2158
+ "@protobufjs/utf8": "^1.1.0",
2159
+ "@types/node": ">=13.7.0",
2160
+ "long": "^5.0.0"
2161
+ },
2162
+ "engines": {
2163
+ "node": ">=12.0.0"
2164
+ }
2165
+ },
2166
+ "node_modules/react": {
2167
+ "version": "19.2.4",
2168
+ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
2169
+ "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
2170
+ "license": "MIT",
2171
+ "engines": {
2172
+ "node": ">=0.10.0"
2173
+ }
2174
+ },
2175
+ "node_modules/react-dom": {
2176
+ "version": "19.2.4",
2177
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
2178
+ "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
2179
+ "license": "MIT",
2180
+ "dependencies": {
2181
+ "scheduler": "^0.27.0"
2182
+ },
2183
+ "peerDependencies": {
2184
+ "react": "^19.2.4"
2185
+ }
2186
+ },
2187
+ "node_modules/react-refresh": {
2188
+ "version": "0.18.0",
2189
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz",
2190
+ "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==",
2191
+ "dev": true,
2192
+ "license": "MIT",
2193
+ "engines": {
2194
+ "node": ">=0.10.0"
2195
+ }
2196
+ },
2197
+ "node_modules/rimraf": {
2198
+ "version": "5.0.10",
2199
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
2200
+ "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==",
2201
+ "license": "ISC",
2202
+ "dependencies": {
2203
+ "glob": "^10.3.7"
2204
+ },
2205
+ "bin": {
2206
+ "rimraf": "dist/esm/bin.mjs"
2207
+ },
2208
+ "funding": {
2209
+ "url": "https://github.com/sponsors/isaacs"
2210
+ }
2211
+ },
2212
+ "node_modules/rollup": {
2213
+ "version": "4.56.0",
2214
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.56.0.tgz",
2215
+ "integrity": "sha512-9FwVqlgUHzbXtDg9RCMgodF3Ua4Na6Gau+Sdt9vyCN4RhHfVKX2DCHy3BjMLTDd47ITDhYAnTwGulWTblJSDLg==",
2216
+ "dev": true,
2217
+ "license": "MIT",
2218
+ "dependencies": {
2219
+ "@types/estree": "1.0.8"
2220
+ },
2221
+ "bin": {
2222
+ "rollup": "dist/bin/rollup"
2223
+ },
2224
+ "engines": {
2225
+ "node": ">=18.0.0",
2226
+ "npm": ">=8.0.0"
2227
+ },
2228
+ "optionalDependencies": {
2229
+ "@rollup/rollup-android-arm-eabi": "4.56.0",
2230
+ "@rollup/rollup-android-arm64": "4.56.0",
2231
+ "@rollup/rollup-darwin-arm64": "4.56.0",
2232
+ "@rollup/rollup-darwin-x64": "4.56.0",
2233
+ "@rollup/rollup-freebsd-arm64": "4.56.0",
2234
+ "@rollup/rollup-freebsd-x64": "4.56.0",
2235
+ "@rollup/rollup-linux-arm-gnueabihf": "4.56.0",
2236
+ "@rollup/rollup-linux-arm-musleabihf": "4.56.0",
2237
+ "@rollup/rollup-linux-arm64-gnu": "4.56.0",
2238
+ "@rollup/rollup-linux-arm64-musl": "4.56.0",
2239
+ "@rollup/rollup-linux-loong64-gnu": "4.56.0",
2240
+ "@rollup/rollup-linux-loong64-musl": "4.56.0",
2241
+ "@rollup/rollup-linux-ppc64-gnu": "4.56.0",
2242
+ "@rollup/rollup-linux-ppc64-musl": "4.56.0",
2243
+ "@rollup/rollup-linux-riscv64-gnu": "4.56.0",
2244
+ "@rollup/rollup-linux-riscv64-musl": "4.56.0",
2245
+ "@rollup/rollup-linux-s390x-gnu": "4.56.0",
2246
+ "@rollup/rollup-linux-x64-gnu": "4.56.0",
2247
+ "@rollup/rollup-linux-x64-musl": "4.56.0",
2248
+ "@rollup/rollup-openbsd-x64": "4.56.0",
2249
+ "@rollup/rollup-openharmony-arm64": "4.56.0",
2250
+ "@rollup/rollup-win32-arm64-msvc": "4.56.0",
2251
+ "@rollup/rollup-win32-ia32-msvc": "4.56.0",
2252
+ "@rollup/rollup-win32-x64-gnu": "4.56.0",
2253
+ "@rollup/rollup-win32-x64-msvc": "4.56.0",
2254
+ "fsevents": "~2.3.2"
2255
+ }
2256
+ },
2257
+ "node_modules/safe-buffer": {
2258
+ "version": "5.2.1",
2259
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
2260
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
2261
+ "funding": [
2262
+ {
2263
+ "type": "github",
2264
+ "url": "https://github.com/sponsors/feross"
2265
+ },
2266
+ {
2267
+ "type": "patreon",
2268
+ "url": "https://www.patreon.com/feross"
2269
+ },
2270
+ {
2271
+ "type": "consulting",
2272
+ "url": "https://feross.org/support"
2273
+ }
2274
+ ],
2275
+ "license": "MIT"
2276
+ },
2277
+ "node_modules/scheduler": {
2278
+ "version": "0.27.0",
2279
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
2280
+ "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
2281
+ "license": "MIT"
2282
+ },
2283
+ "node_modules/semver": {
2284
+ "version": "6.3.1",
2285
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
2286
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
2287
+ "dev": true,
2288
+ "license": "ISC",
2289
+ "bin": {
2290
+ "semver": "bin/semver.js"
2291
+ }
2292
+ },
2293
+ "node_modules/shebang-command": {
2294
+ "version": "2.0.0",
2295
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
2296
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
2297
+ "license": "MIT",
2298
+ "dependencies": {
2299
+ "shebang-regex": "^3.0.0"
2300
+ },
2301
+ "engines": {
2302
+ "node": ">=8"
2303
+ }
2304
+ },
2305
+ "node_modules/shebang-regex": {
2306
+ "version": "3.0.0",
2307
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
2308
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
2309
+ "license": "MIT",
2310
+ "engines": {
2311
+ "node": ">=8"
2312
+ }
2313
+ },
2314
+ "node_modules/signal-exit": {
2315
+ "version": "4.1.0",
2316
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
2317
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
2318
+ "license": "ISC",
2319
+ "engines": {
2320
+ "node": ">=14"
2321
+ },
2322
+ "funding": {
2323
+ "url": "https://github.com/sponsors/isaacs"
2324
+ }
2325
+ },
2326
+ "node_modules/source-map-js": {
2327
+ "version": "1.2.1",
2328
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
2329
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
2330
+ "dev": true,
2331
+ "license": "BSD-3-Clause",
2332
+ "engines": {
2333
+ "node": ">=0.10.0"
2334
+ }
2335
+ },
2336
+ "node_modules/string-width": {
2337
+ "version": "5.1.2",
2338
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
2339
+ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
2340
+ "license": "MIT",
2341
+ "dependencies": {
2342
+ "eastasianwidth": "^0.2.0",
2343
+ "emoji-regex": "^9.2.2",
2344
+ "strip-ansi": "^7.0.1"
2345
+ },
2346
+ "engines": {
2347
+ "node": ">=12"
2348
+ },
2349
+ "funding": {
2350
+ "url": "https://github.com/sponsors/sindresorhus"
2351
+ }
2352
+ },
2353
+ "node_modules/string-width-cjs": {
2354
+ "name": "string-width",
2355
+ "version": "4.2.3",
2356
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
2357
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
2358
+ "license": "MIT",
2359
+ "dependencies": {
2360
+ "emoji-regex": "^8.0.0",
2361
+ "is-fullwidth-code-point": "^3.0.0",
2362
+ "strip-ansi": "^6.0.1"
2363
+ },
2364
+ "engines": {
2365
+ "node": ">=8"
2366
+ }
2367
+ },
2368
+ "node_modules/string-width-cjs/node_modules/ansi-regex": {
2369
+ "version": "5.0.1",
2370
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
2371
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
2372
+ "license": "MIT",
2373
+ "engines": {
2374
+ "node": ">=8"
2375
+ }
2376
+ },
2377
+ "node_modules/string-width-cjs/node_modules/emoji-regex": {
2378
+ "version": "8.0.0",
2379
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
2380
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
2381
+ "license": "MIT"
2382
+ },
2383
+ "node_modules/string-width-cjs/node_modules/strip-ansi": {
2384
+ "version": "6.0.1",
2385
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
2386
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
2387
+ "license": "MIT",
2388
+ "dependencies": {
2389
+ "ansi-regex": "^5.0.1"
2390
+ },
2391
+ "engines": {
2392
+ "node": ">=8"
2393
+ }
2394
+ },
2395
+ "node_modules/strip-ansi": {
2396
+ "version": "7.1.2",
2397
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
2398
+ "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
2399
+ "license": "MIT",
2400
+ "dependencies": {
2401
+ "ansi-regex": "^6.0.1"
2402
+ },
2403
+ "engines": {
2404
+ "node": ">=12"
2405
+ },
2406
+ "funding": {
2407
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
2408
+ }
2409
+ },
2410
+ "node_modules/strip-ansi-cjs": {
2411
+ "name": "strip-ansi",
2412
+ "version": "6.0.1",
2413
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
2414
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
2415
+ "license": "MIT",
2416
+ "dependencies": {
2417
+ "ansi-regex": "^5.0.1"
2418
+ },
2419
+ "engines": {
2420
+ "node": ">=8"
2421
+ }
2422
+ },
2423
+ "node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
2424
+ "version": "5.0.1",
2425
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
2426
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
2427
+ "license": "MIT",
2428
+ "engines": {
2429
+ "node": ">=8"
2430
+ }
2431
+ },
2432
+ "node_modules/tinyglobby": {
2433
+ "version": "0.2.15",
2434
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
2435
+ "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
2436
+ "dev": true,
2437
+ "license": "MIT",
2438
+ "dependencies": {
2439
+ "fdir": "^6.5.0",
2440
+ "picomatch": "^4.0.3"
2441
+ },
2442
+ "engines": {
2443
+ "node": ">=12.0.0"
2444
+ },
2445
+ "funding": {
2446
+ "url": "https://github.com/sponsors/SuperchupuDev"
2447
+ }
2448
+ },
2449
+ "node_modules/typescript": {
2450
+ "version": "5.8.3",
2451
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
2452
+ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
2453
+ "dev": true,
2454
+ "license": "Apache-2.0",
2455
+ "bin": {
2456
+ "tsc": "bin/tsc",
2457
+ "tsserver": "bin/tsserver"
2458
+ },
2459
+ "engines": {
2460
+ "node": ">=14.17"
2461
+ }
2462
+ },
2463
+ "node_modules/undici-types": {
2464
+ "version": "6.21.0",
2465
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
2466
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
2467
+ "license": "MIT"
2468
+ },
2469
+ "node_modules/update-browserslist-db": {
2470
+ "version": "1.2.3",
2471
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
2472
+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
2473
+ "dev": true,
2474
+ "funding": [
2475
+ {
2476
+ "type": "opencollective",
2477
+ "url": "https://opencollective.com/browserslist"
2478
+ },
2479
+ {
2480
+ "type": "tidelift",
2481
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
2482
+ },
2483
+ {
2484
+ "type": "github",
2485
+ "url": "https://github.com/sponsors/ai"
2486
+ }
2487
+ ],
2488
+ "license": "MIT",
2489
+ "dependencies": {
2490
+ "escalade": "^3.2.0",
2491
+ "picocolors": "^1.1.1"
2492
+ },
2493
+ "bin": {
2494
+ "update-browserslist-db": "cli.js"
2495
+ },
2496
+ "peerDependencies": {
2497
+ "browserslist": ">= 4.21.0"
2498
+ }
2499
+ },
2500
+ "node_modules/vite": {
2501
+ "version": "6.4.1",
2502
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
2503
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
2504
+ "dev": true,
2505
+ "license": "MIT",
2506
+ "dependencies": {
2507
+ "esbuild": "^0.25.0",
2508
+ "fdir": "^6.4.4",
2509
+ "picomatch": "^4.0.2",
2510
+ "postcss": "^8.5.3",
2511
+ "rollup": "^4.34.9",
2512
+ "tinyglobby": "^0.2.13"
2513
+ },
2514
+ "bin": {
2515
+ "vite": "bin/vite.js"
2516
+ },
2517
+ "engines": {
2518
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
2519
+ },
2520
+ "funding": {
2521
+ "url": "https://github.com/vitejs/vite?sponsor=1"
2522
+ },
2523
+ "optionalDependencies": {
2524
+ "fsevents": "~2.3.3"
2525
+ },
2526
+ "peerDependencies": {
2527
+ "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
2528
+ "jiti": ">=1.21.0",
2529
+ "less": "*",
2530
+ "lightningcss": "^1.21.0",
2531
+ "sass": "*",
2532
+ "sass-embedded": "*",
2533
+ "stylus": "*",
2534
+ "sugarss": "*",
2535
+ "terser": "^5.16.0",
2536
+ "tsx": "^4.8.1",
2537
+ "yaml": "^2.4.2"
2538
+ },
2539
+ "peerDependenciesMeta": {
2540
+ "@types/node": {
2541
+ "optional": true
2542
+ },
2543
+ "jiti": {
2544
+ "optional": true
2545
+ },
2546
+ "less": {
2547
+ "optional": true
2548
+ },
2549
+ "lightningcss": {
2550
+ "optional": true
2551
+ },
2552
+ "sass": {
2553
+ "optional": true
2554
+ },
2555
+ "sass-embedded": {
2556
+ "optional": true
2557
+ },
2558
+ "stylus": {
2559
+ "optional": true
2560
+ },
2561
+ "sugarss": {
2562
+ "optional": true
2563
+ },
2564
+ "terser": {
2565
+ "optional": true
2566
+ },
2567
+ "tsx": {
2568
+ "optional": true
2569
+ },
2570
+ "yaml": {
2571
+ "optional": true
2572
+ }
2573
+ }
2574
+ },
2575
+ "node_modules/web-streams-polyfill": {
2576
+ "version": "3.3.3",
2577
+ "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
2578
+ "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
2579
+ "license": "MIT",
2580
+ "engines": {
2581
+ "node": ">= 8"
2582
+ }
2583
+ },
2584
+ "node_modules/which": {
2585
+ "version": "2.0.2",
2586
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
2587
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
2588
+ "license": "ISC",
2589
+ "dependencies": {
2590
+ "isexe": "^2.0.0"
2591
+ },
2592
+ "bin": {
2593
+ "node-which": "bin/node-which"
2594
+ },
2595
+ "engines": {
2596
+ "node": ">= 8"
2597
+ }
2598
+ },
2599
+ "node_modules/wrap-ansi": {
2600
+ "version": "8.1.0",
2601
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
2602
+ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
2603
+ "license": "MIT",
2604
+ "dependencies": {
2605
+ "ansi-styles": "^6.1.0",
2606
+ "string-width": "^5.0.1",
2607
+ "strip-ansi": "^7.0.1"
2608
+ },
2609
+ "engines": {
2610
+ "node": ">=12"
2611
+ },
2612
+ "funding": {
2613
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
2614
+ }
2615
+ },
2616
+ "node_modules/wrap-ansi-cjs": {
2617
+ "name": "wrap-ansi",
2618
+ "version": "7.0.0",
2619
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
2620
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
2621
+ "license": "MIT",
2622
+ "dependencies": {
2623
+ "ansi-styles": "^4.0.0",
2624
+ "string-width": "^4.1.0",
2625
+ "strip-ansi": "^6.0.0"
2626
+ },
2627
+ "engines": {
2628
+ "node": ">=10"
2629
+ },
2630
+ "funding": {
2631
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
2632
+ }
2633
+ },
2634
+ "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
2635
+ "version": "5.0.1",
2636
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
2637
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
2638
+ "license": "MIT",
2639
+ "engines": {
2640
+ "node": ">=8"
2641
+ }
2642
+ },
2643
+ "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
2644
+ "version": "4.3.0",
2645
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
2646
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
2647
+ "license": "MIT",
2648
+ "dependencies": {
2649
+ "color-convert": "^2.0.1"
2650
+ },
2651
+ "engines": {
2652
+ "node": ">=8"
2653
+ },
2654
+ "funding": {
2655
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
2656
+ }
2657
+ },
2658
+ "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
2659
+ "version": "8.0.0",
2660
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
2661
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
2662
+ "license": "MIT"
2663
+ },
2664
+ "node_modules/wrap-ansi-cjs/node_modules/string-width": {
2665
+ "version": "4.2.3",
2666
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
2667
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
2668
+ "license": "MIT",
2669
+ "dependencies": {
2670
+ "emoji-regex": "^8.0.0",
2671
+ "is-fullwidth-code-point": "^3.0.0",
2672
+ "strip-ansi": "^6.0.1"
2673
+ },
2674
+ "engines": {
2675
+ "node": ">=8"
2676
+ }
2677
+ },
2678
+ "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
2679
+ "version": "6.0.1",
2680
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
2681
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
2682
+ "license": "MIT",
2683
+ "dependencies": {
2684
+ "ansi-regex": "^5.0.1"
2685
+ },
2686
+ "engines": {
2687
+ "node": ">=8"
2688
+ }
2689
+ },
2690
+ "node_modules/ws": {
2691
+ "version": "8.19.0",
2692
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
2693
+ "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
2694
+ "license": "MIT",
2695
+ "engines": {
2696
+ "node": ">=10.0.0"
2697
+ },
2698
+ "peerDependencies": {
2699
+ "bufferutil": "^4.0.1",
2700
+ "utf-8-validate": ">=5.0.2"
2701
+ },
2702
+ "peerDependenciesMeta": {
2703
+ "bufferutil": {
2704
+ "optional": true
2705
+ },
2706
+ "utf-8-validate": {
2707
+ "optional": true
2708
+ }
2709
+ }
2710
+ },
2711
+ "node_modules/yallist": {
2712
+ "version": "3.1.1",
2713
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
2714
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
2715
+ "dev": true,
2716
+ "license": "ISC"
2717
+ }
2718
+ }
2719
+ }
package.json ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "briefly-ai",
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
+ "@google/genai": "^1.38.0",
13
+ "@google/generative-ai": "^0.24.1",
14
+ "react": "^19.2.4",
15
+ "react-dom": "^19.2.4"
16
+ },
17
+ "devDependencies": {
18
+ "@types/node": "^22.14.0",
19
+ "@vitejs/plugin-react": "^5.0.0",
20
+ "typescript": "~5.8.2",
21
+ "vite": "^6.2.0"
22
+ }
23
+ }
services/api.ts ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Chat API Service
2
+ import { Chat, Message, Document } from '../types';
3
+
4
+ const API_BASE = 'http://localhost:4000';
5
+
6
+ // Create a new chat
7
+ export async function createChat(title?: string): Promise<Chat> {
8
+ const res = await fetch(`${API_BASE}/chats`, {
9
+ method: 'POST',
10
+ headers: { 'Content-Type': 'application/json' },
11
+ body: JSON.stringify({ title: title || 'New Chat' }),
12
+ });
13
+
14
+ if (!res.ok) {
15
+ const data = await res.json();
16
+ throw new Error(data.detail || 'Failed to create chat');
17
+ }
18
+
19
+ return res.json();
20
+ }
21
+
22
+ // Get all chats
23
+ export async function getChats(): Promise<Chat[]> {
24
+ const res = await fetch(`${API_BASE}/chats`);
25
+
26
+ if (!res.ok) {
27
+ throw new Error('Failed to fetch chats');
28
+ }
29
+
30
+ const data = await res.json();
31
+ return data.chats;
32
+ }
33
+
34
+ // Get messages for a chat
35
+ export async function getMessages(chatId: string): Promise<Message[]> {
36
+ const res = await fetch(`${API_BASE}/chats/${chatId}/messages`);
37
+
38
+ if (!res.ok) {
39
+ throw new Error('Failed to fetch messages');
40
+ }
41
+
42
+ const data = await res.json();
43
+ return data.messages;
44
+ }
45
+
46
+ // Send a message and get AI response
47
+ export async function sendMessage(chatId: string, content: string): Promise<{
48
+ user_message: Message;
49
+ assistant_message: Message;
50
+ }> {
51
+ const res = await fetch(`${API_BASE}/chats/${chatId}/messages`, {
52
+ method: 'POST',
53
+ headers: { 'Content-Type': 'application/json' },
54
+ body: JSON.stringify({ content }),
55
+ });
56
+
57
+ if (!res.ok) {
58
+ const data = await res.json();
59
+ throw new Error(data.detail || 'Failed to send message');
60
+ }
61
+
62
+ return res.json();
63
+ }
64
+
65
+ // Delete a chat
66
+ export async function deleteChat(chatId: string): Promise<void> {
67
+ const res = await fetch(`${API_BASE}/chats/${chatId}`, {
68
+ method: 'DELETE',
69
+ });
70
+
71
+ if (!res.ok) {
72
+ throw new Error('Failed to delete chat');
73
+ }
74
+ }
75
+
76
+ // ==============================
77
+ // DOCUMENT API FUNCTIONS
78
+ // ==============================
79
+
80
+ // Get all documents
81
+ export async function getDocuments(): Promise<Document[]> {
82
+ const res = await fetch(`${API_BASE}/documents`);
83
+
84
+ if (!res.ok) {
85
+ throw new Error('Failed to fetch documents');
86
+ }
87
+
88
+ const data = await res.json();
89
+ return data.documents;
90
+ }
91
+
92
+ // Upload a document
93
+ export async function uploadDocument(file: File): Promise<Document> {
94
+ const formData = new FormData();
95
+ formData.append('file', file);
96
+
97
+ const res = await fetch(`${API_BASE}/documents`, {
98
+ method: 'POST',
99
+ body: formData,
100
+ });
101
+
102
+ if (!res.ok) {
103
+ const data = await res.json().catch(() => ({}));
104
+ throw new Error(data.detail || 'Failed to upload document');
105
+ }
106
+
107
+ return res.json();
108
+ }
109
+
110
+ // Delete a document
111
+ export async function deleteDocument(docId: string): Promise<void> {
112
+ const res = await fetch(`${API_BASE}/documents/${docId}`, {
113
+ method: 'DELETE',
114
+ });
115
+
116
+ if (!res.ok) {
117
+ throw new Error('Failed to delete document');
118
+ }
119
+ }
120
+
121
+ // Legacy summarize function (backwards compatibility)
122
+ export async function summarizeText(text: string): Promise<string> {
123
+ const res = await fetch(`${API_BASE}/ask`, {
124
+ method: 'POST',
125
+ headers: { 'Content-Type': 'application/json' },
126
+ body: JSON.stringify({ question: text }),
127
+ });
128
+
129
+ const data = await res.json();
130
+ console.log("datalar", data);
131
+
132
+ if (!res.ok) throw new Error(data.error || 'Unexpected error');
133
+
134
+ return data.answer;
135
+ }
services/gemini.ts ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // // src/services/gemini.ts
2
+ // export async function summarizeText(text: string): Promise<string> {
3
+
4
+ // const res = await fetch("http://localhost:8000/generate", {
5
+ // method: "POST",
6
+ // headers: {
7
+ // "Content-Type": "application/json",
8
+ // },
9
+ // body: JSON.stringify({ prompt: text }),
10
+ // });
11
+
12
+ // const data = await res.json();
13
+ // console.log("Gemini API response data:", data);
14
+
15
+
16
+ // if (!res.ok) throw new Error(data.error || "Unexpected error");
17
+
18
+ // return data.response;
19
+ // }
20
+
21
+ // // const answer = await summarizeText("mustaqillik kuni qachon");
22
+ // // console.log("Answer from Gemini:", answer);
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,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ export interface SummaryState {
3
+ originalText: string;
4
+ summary: string;
5
+ isLoading: boolean;
6
+ error: string | null;
7
+ }
8
+
9
+ export interface SummaryResponse {
10
+ summary: string;
11
+ error?: string;
12
+ }
13
+
14
+ // Chat Types
15
+ export interface Chat {
16
+ id: string;
17
+ title: string;
18
+ created_at: string;
19
+ }
20
+
21
+ export interface Message {
22
+ id: string;
23
+ chat_id: string;
24
+ role: 'user' | 'assistant';
25
+ content: string;
26
+ timestamp: string;
27
+ }
28
+
29
+ // Document Types
30
+ export interface Document {
31
+ id: string;
32
+ filename: string;
33
+ upload_date: string;
34
+ status: string;
35
+ }
36
+
37
+ export interface ChatState {
38
+ chats: Chat[];
39
+ activeChat: Chat | null;
40
+ messages: Message[];
41
+ isLoading: boolean;
42
+ isSending: boolean;
43
+ error: string | null;
44
+ }
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
+ });