ldostadi commited on
Commit
41fb074
·
verified ·
1 Parent(s): 2acd798

Update app.py from anycoder

Browse files
Files changed (1) hide show
  1. app.py +656 -0
app.py ADDED
@@ -0,0 +1,656 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import os
3
+ import sqlite3
4
+ import json
5
+ import hashlib
6
+ from datetime import datetime
7
+ from typing import List, Dict, Any, Tuple, Optional
8
+ import numpy as np
9
+ from sklearn.feature_extraction.text import TfidfVectorizer
10
+ from sklearn.metrics.pairwise import cosine_similarity
11
+ import threading
12
+
13
+ from utils import (
14
+ process_document,
15
+ extract_axioms,
16
+ generate_response,
17
+ get_embedding,
18
+ compute_similarity,
19
+ Document,
20
+ Axiom,
21
+ ActivityLog
22
+ )
23
+
24
+ # Initialize database
25
+ DB_PATH = "rag_nexus.db"
26
+ conn = sqlite3.connect(DB_PATH, check_same_thread=False)
27
+ cursor = conn.cursor()
28
+
29
+ # Create tables
30
+ cursor.execute("""
31
+ CREATE TABLE IF NOT EXISTS documents (
32
+ id TEXT PRIMARY KEY,
33
+ name TEXT,
34
+ content TEXT,
35
+ size INTEGER,
36
+ uploaded_at TEXT,
37
+ chunk_count INTEGER
38
+ )
39
+ """)
40
+
41
+ cursor.execute("""
42
+ CREATE TABLE IF NOT EXISTS axioms (
43
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
44
+ doc_id TEXT,
45
+ source TEXT,
46
+ axiom TEXT,
47
+ confidence REAL,
48
+ FOREIGN KEY (doc_id) REFERENCES documents (id)
49
+ )
50
+ """)
51
+
52
+ cursor.execute("""
53
+ CREATE TABLE IF NOT EXISTS activity (
54
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
55
+ action TEXT,
56
+ details TEXT,
57
+ timestamp TEXT
58
+ )
59
+ """)
60
+
61
+ conn.commit()
62
+
63
+ # Thread-local storage for database connections
64
+ thread_local = threading.local()
65
+
66
+ def get_db():
67
+ """Get thread-local database connection"""
68
+ if not hasattr(thread_local, 'conn'):
69
+ thread_local.conn = sqlite3.connect(DB_PATH)
70
+ return thread_local.conn
71
+
72
+ class RAGState:
73
+ def __init__(self):
74
+ self.vectorizer = TfidfVectorizer(max_features=1000, stop_words='english')
75
+ self.document_chunks = []
76
+ self.chunk_metadata = []
77
+ self.is_initialized = False
78
+
79
+ def initialize_models(self):
80
+ """Initialize models (simulated)"""
81
+ if not self.is_initialized:
82
+ # Load existing documents
83
+ conn = get_db()
84
+ cursor = conn.cursor()
85
+ cursor.execute("SELECT id, content FROM documents")
86
+ docs = cursor.fetchall()
87
+
88
+ if docs:
89
+ chunks = []
90
+ metadata = []
91
+ for doc_id, content in docs:
92
+ doc_chunks = [content[i:i+500] for i in range(0, len(content), 500)]
93
+ chunks.extend(doc_chunks)
94
+ metadata.extend([{"doc_id": doc_id, "chunk_idx": i} for i in range(len(doc_chunks))])
95
+
96
+ if chunks:
97
+ self.vectorizer.fit(chunks)
98
+ self.document_chunks = chunks
99
+ self.chunk_metadata = metadata
100
+
101
+ self.is_initialized = True
102
+
103
+ def get_state():
104
+ """Get global state"""
105
+ if not hasattr(get_state, 'state'):
106
+ get_state.state = RAGState()
107
+ return get_state.state
108
+
109
+ def log_activity(action: str, details: Dict[str, Any]):
110
+ """Log activity to database"""
111
+ conn = get_db()
112
+ cursor = conn.cursor()
113
+ cursor.execute(
114
+ "INSERT INTO activity (action, details, timestamp) VALUES (?, ?, ?)",
115
+ (action, json.dumps(details), datetime.now().isoformat())
116
+ )
117
+ conn.commit()
118
+
119
+ def get_stats():
120
+ """Get system statistics"""
121
+ conn = get_db()
122
+ cursor = conn.cursor()
123
+
124
+ cursor.execute("SELECT COUNT(*) FROM documents")
125
+ doc_count = cursor.fetchone()[0]
126
+
127
+ cursor.execute("SELECT COUNT(*) FROM axioms")
128
+ axiom_count = cursor.fetchone()[0]
129
+
130
+ cursor.execute("SELECT SUM(size) FROM documents")
131
+ storage = cursor.fetchone()[0] or 0
132
+
133
+ return {
134
+ "doc_count": doc_count,
135
+ "axiom_count": axiom_count,
136
+ "storage_mb": round(storage / 1024 / 1024, 2)
137
+ }
138
+
139
+ def load_documents():
140
+ """Load all documents"""
141
+ conn = get_db()
142
+ cursor = conn.cursor()
143
+ cursor.execute("SELECT id, name, size, uploaded_at FROM documents ORDER BY uploaded_at DESC")
144
+ docs = cursor.fetchall()
145
+
146
+ if not docs:
147
+ return [["No documents found", "", "", ""]]
148
+
149
+ return [[doc[1], f"{doc[2]} bytes", doc[3], doc[0]] for doc in docs]
150
+
151
+ def load_axioms(source_filter: str = ""):
152
+ """Load axioms with optional source filter"""
153
+ conn = get_db()
154
+ cursor = conn.cursor()
155
+
156
+ if source_filter:
157
+ cursor.execute("""
158
+ SELECT a.id, a.source, a.axiom, a.confidence, d.name
159
+ FROM axioms a
160
+ JOIN documents d ON a.doc_id = d.id
161
+ WHERE d.name LIKE ?
162
+ ORDER BY a.confidence DESC
163
+ """, (f"%{source_filter}%",))
164
+ else:
165
+ cursor.execute("""
166
+ SELECT a.id, a.source, a.axiom, a.confidence, d.name
167
+ FROM axioms a
168
+ JOIN documents d ON a.doc_id = d.id
169
+ ORDER BY a.confidence DESC
170
+ """)
171
+
172
+ axioms = cursor.fetchall()
173
+
174
+ if not axioms:
175
+ return [["No axioms found", "", "", "", ""]]
176
+
177
+ return [[ax[4], ax[1], ax[2][:100] + "...", f"{ax[3]:.2f}", str(ax[0])] for ax in axioms]
178
+
179
+ def load_activity():
180
+ """Load recent activity"""
181
+ conn = get_db()
182
+ cursor = conn.cursor()
183
+ cursor.execute("SELECT action, details, timestamp FROM activity ORDER BY timestamp DESC LIMIT 20")
184
+ activities = cursor.fetchall()
185
+
186
+ if not activities:
187
+ return [["No activity yet", "", ""]]
188
+
189
+ return [[act[0], json.loads(act[1]).get('description', ''), act[2]] for act in activities]
190
+
191
+ def process_uploaded_files(files: List[str]) -> Tuple[str, str]:
192
+ """Process uploaded files and return status"""
193
+ if not files:
194
+ return "No files uploaded", "⚠️"
195
+
196
+ state = get_state()
197
+ success_count = 0
198
+ total_count = len(files)
199
+
200
+ for file_path in files:
201
+ try:
202
+ # Process document
203
+ doc = process_document(file_path)
204
+
205
+ # Save to database
206
+ conn = get_db()
207
+ cursor = conn.cursor()
208
+ cursor.execute(
209
+ "INSERT INTO documents (id, name, content, size, uploaded_at, chunk_count) VALUES (?, ?, ?, ?, ?, ?)",
210
+ (doc.id, doc.name, doc.content, doc.size, doc.uploaded_at, doc.chunk_count)
211
+ )
212
+
213
+ # Extract axioms
214
+ axioms = extract_axioms(doc.content, doc.id)
215
+ for axiom in axioms:
216
+ cursor.execute(
217
+ "INSERT INTO axioms (doc_id, source, axiom, confidence) VALUES (?, ?, ?, ?)",
218
+ (doc.id, axiom.source, axiom.text, axiom.confidence)
219
+ )
220
+
221
+ conn.commit()
222
+
223
+ # Update vector store
224
+ chunks = [doc.content[i:i+500] for i in range(0, len(doc.content), 500)]
225
+ state.document_chunks.extend(chunks)
226
+ state.chunk_metadata.extend([{"doc_id": doc.id, "chunk_idx": i} for i in range(len(chunks))])
227
+
228
+ # Refit vectorizer if needed
229
+ if state.document_chunks:
230
+ state.vectorizer.fit(state.document_chunks)
231
+
232
+ log_activity("document_uploaded", {
233
+ "name": doc.name,
234
+ "size": doc.size,
235
+ "chunks": doc.chunk_count
236
+ })
237
+
238
+ success_count += 1
239
+
240
+ except Exception as e:
241
+ log_activity("upload_failed", {
242
+ "file": os.path.basename(file_path),
243
+ "error": str(e)
244
+ })
245
+
246
+ # Clean up temporary files
247
+ for file_path in files:
248
+ try:
249
+ os.unlink(file_path)
250
+ except:
251
+ pass
252
+
253
+ return f"Processed {success_count}/{total_count} files", "✅" if success_count == total_count else "⚠️"
254
+
255
+ def generate_rag_response(query: str, use_axioms: bool, use_context: bool) -> Tuple[str, str]:
256
+ """Generate response using RAG"""
257
+ if not query.strip():
258
+ return "Please enter a query", ""
259
+
260
+ state = get_state()
261
+ state.initialize_models()
262
+
263
+ # Retrieve context
264
+ context = ""
265
+ retrieved_docs = []
266
+
267
+ if use_context and state.document_chunks:
268
+ try:
269
+ query_vec = state.vectorizer.transform([query])
270
+ doc_vecs = state.vectorizer.transform(state.document_chunks)
271
+ similarities = cosine_similarity(query_vec, doc_vecs).flatten()
272
+
273
+ # Get top 3 chunks
274
+ top_indices = np.argsort(similarities)[-3:][::-1]
275
+
276
+ for idx in top_indices:
277
+ if similarities[idx] > 0.1:
278
+ chunk = state.document_chunks[idx]
279
+ doc_id = state.chunk_metadata[idx]["doc_id"]
280
+ conn = get_db()
281
+ cursor = conn.cursor()
282
+ cursor.execute("SELECT name FROM documents WHERE id = ?", (doc_id,))
283
+ doc_name = cursor.fetchone()[0]
284
+
285
+ context += f"\n\n--- From {doc_name} ---\n{chunk}"
286
+ retrieved_docs.append(f"{doc_name} (similarity: {similarities[idx]:.2f})")
287
+ except:
288
+ context = ""
289
+ retrieved_docs = ["No relevant context found"]
290
+
291
+ # Get axioms
292
+ axioms = []
293
+ if use_axioms:
294
+ conn = get_db()
295
+ cursor = conn.cursor()
296
+ cursor.execute("SELECT axiom FROM axioms ORDER BY RANDOM() LIMIT 5")
297
+ axioms = [row[0] for row in cursor.fetchall()]
298
+
299
+ # Generate response
300
+ response = generate_response(query, context, axioms)
301
+
302
+ # Log activity
303
+ log_activity("response_generated", {
304
+ "query": query[:100],
305
+ "used_axioms": use_axioms,
306
+ "used_context": use_context
307
+ })
308
+
309
+ # Format context info
310
+ context_info = "\n".join(retrieved_docs) if retrieved_docs else "No context retrieved"
311
+
312
+ return response, context_info
313
+
314
+ def clear_all_data():
315
+ """Clear all data from database"""
316
+ conn = get_db()
317
+ cursor = conn.cursor()
318
+ cursor.execute("DELETE FROM documents")
319
+ cursor.execute("DELETE FROM axioms")
320
+ cursor.execute("DELETE FROM activity")
321
+ conn.commit()
322
+
323
+ # Reset state
324
+ state = get_state()
325
+ state.document_chunks = []
326
+ state.chunk_metadata = []
327
+
328
+ log_activity("data_cleared", {"all": True})
329
+
330
+ return "All data cleared successfully", "✅"
331
+
332
+ def export_axioms():
333
+ """Export axioms as JSON"""
334
+ conn = get_db()
335
+ cursor = conn.cursor()
336
+ cursor.execute("""
337
+ SELECT d.name as document, a.source, a.axiom, a.confidence
338
+ FROM axioms a
339
+ JOIN documents d ON a.doc_id = d.id
340
+ """)
341
+ axioms = [{"document": row[0], "source": row[1], "axiom": row[2], "confidence": row[3]}
342
+ for row in cursor.fetchall()]
343
+
344
+ if not axioms:
345
+ return "No axioms to export", "⚠️"
346
+
347
+ filename = f"axioms_export_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
348
+ with open(filename, 'w') as f:
349
+ json.dump(axioms, f, indent=2)
350
+
351
+ log_activity("axioms_exported", {"count": len(axioms), "file": filename})
352
+
353
+ return f"Exported {len(axioms)} axioms to {filename}", "✅"
354
+
355
+ # Initialize app state on load
356
+ def initialize_app():
357
+ state = get_state()
358
+ state.initialize_models()
359
+ return "✅ Models initialized"
360
+
361
+ # Create Gradio interface
362
+ with gr.Blocks() as demo:
363
+ gr.Markdown(
364
+ """
365
+ # 🔮 RAG Nexus
366
+ ### Intelligent Document Analysis & Axiom Extraction System
367
+ **Built with anycoder** | [View on Hugging Face](https://huggingface.co/spaces/akhaliq/anycoder)
368
+ """
369
+ )
370
+
371
+ # Status bar
372
+ with gr.Row():
373
+ status_text = gr.Textbox("Initializing...", label="System Status", scale=4)
374
+ init_btn = gr.Button("🔄 Reinitialize", scale=1)
375
+
376
+ # Tabs
377
+ with gr.Tabs() as tabs:
378
+ # Upload Tab
379
+ with gr.TabItem("📤 Upload", id="upload"):
380
+ gr.Markdown("### Upload Documents for Analysis")
381
+
382
+ file_output = gr.File(
383
+ label="Drop files here or click to browse",
384
+ file_count="multiple",
385
+ file_types=[".txt", ".md", ".pdf", ".doc", ".docx"]
386
+ )
387
+
388
+ upload_btn = gr.Button("🚀 Process Files", variant="primary")
389
+ upload_status = gr.Textbox(label="Upload Status", interactive=False)
390
+
391
+ with gr.Accordion("📋 Upload Queue", open=False):
392
+ upload_queue = gr.Dataframe(
393
+ headers=["File", "Status", "Size (bytes)"],
394
+ datatype=["str", "str", "number"],
395
+ label="Processed Files"
396
+ )
397
+
398
+ # Documents Tab
399
+ with gr.TabItem("📚 Documents", id="documents"):
400
+ gr.Markdown("### Indexed Documents")
401
+
402
+ with gr.Row():
403
+ doc_search = gr.Textbox(
404
+ placeholder="Search documents...",
405
+ label="Search",
406
+ scale=3
407
+ )
408
+ clear_docs_btn = gr.Button("🗑️ Clear All", variant="stop", scale=1)
409
+
410
+ documents_table = gr.Dataframe(
411
+ headers=["Name", "Size", "Uploaded", "ID"],
412
+ datatype=["str", "str", "str", "str"],
413
+ label="Documents",
414
+ wrap=True
415
+ )
416
+
417
+ doc_search.change(
418
+ fn=lambda search: load_documents(),
419
+ inputs=doc_search,
420
+ outputs=documents_table,
421
+ api_visibility="private"
422
+ )
423
+
424
+ # Axioms Tab
425
+ with gr.TabItem("⚡ Axioms", id="axioms"):
426
+ gr.Markdown("### Extracted Axioms")
427
+
428
+ with gr.Row():
429
+ axiom_search = gr.Textbox(
430
+ placeholder="Search axioms...",
431
+ label="Search",
432
+ scale=2
433
+ )
434
+ axiom_filter = gr.Dropdown(
435
+ choices=[],
436
+ label="Filter by Document",
437
+ scale=1
438
+ )
439
+ export_axioms_btn = gr.Button("💾 Export JSON", scale=1)
440
+
441
+ axioms_table = gr.Dataframe(
442
+ headers=["Document", "Source", "Axiom", "Confidence", "ID"],
443
+ datatype=["str", "str", "str", "number", "str"],
444
+ label="Axioms",
445
+ wrap=True
446
+ )
447
+
448
+ export_status = gr.Textbox(label="Export Status", interactive=False)
449
+
450
+ # Generate Tab
451
+ with gr.TabItem("🤖 Generate", id="generate"):
452
+ gr.Markdown("### Intelligent Response Generation")
453
+
454
+ query_input = gr.Textbox(
455
+ label="Enter your query",
456
+ placeholder="Ask anything about your documents... (e.g., 'What are the fundamental principles based on the uploaded documents?')",
457
+ lines=4,
458
+ max_lines=8
459
+ )
460
+
461
+ with gr.Row():
462
+ use_axioms = gr.Checkbox(label="Use Axioms", value=True)
463
+ use_context = gr.Checkbox(label="Use Context (RAG)", value=True)
464
+
465
+ generate_btn = gr.Button("🚀 Generate Response", variant="primary")
466
+
467
+ with gr.Group():
468
+ response_output = gr.Markdown(
469
+ label="Generated Response",
470
+ show_copy_button=True
471
+ )
472
+
473
+ with gr.Accordion("📚 Retrieved Context & Axioms", open=False):
474
+ context_output = gr.Textbox(
475
+ label="Retrieved Documents",
476
+ lines=5,
477
+ interactive=False
478
+ )
479
+
480
+ query_stats = gr.Textbox(
481
+ label="Query Statistics",
482
+ interactive=False,
483
+ visible=False
484
+ )
485
+
486
+ # Analytics Tab
487
+ with gr.TabItem("📊 Analytics", id="analytics"):
488
+ gr.Markdown("### System Analytics")
489
+
490
+ with gr.Row():
491
+ with gr.Column():
492
+ doc_count_label = gr.Label(value="0", label="📄 Documents", show_label=True)
493
+ with gr.Column():
494
+ axiom_count_label = gr.Label(value="0", label="⚡ Axioms", show_label=True)
495
+ with gr.Column():
496
+ storage_label = gr.Label(value="0MB", label="💾 Storage Used", show_label=True)
497
+
498
+ with gr.Accordion("📈 Recent Activity", open=True):
499
+ activity_log = gr.Dataframe(
500
+ headers=["Action", "Details", "Timestamp"],
501
+ datatype=["str", "str", "str"],
502
+ label="Activity Log",
503
+ wrap=True,
504
+ max_height=300
505
+ )
506
+
507
+ # Event handlers
508
+ init_btn.click(
509
+ fn=initialize_app,
510
+ outputs=status_text,
511
+ api_visibility="private"
512
+ )
513
+
514
+ # Upload events
515
+ def process_and_update(files):
516
+ if not files:
517
+ return "No files selected", []
518
+
519
+ # Process files
520
+ status, icon = process_uploaded_files(files)
521
+
522
+ # Create queue table
523
+ queue_data = []
524
+ for f in files:
525
+ name = os.path.basename(f)
526
+ size = os.path.getsize(f) if os.path.exists(f) else 0
527
+ queue_data.append([name, "✅ Processed", size])
528
+
529
+ return f"{icon} {status}", queue_data
530
+
531
+ upload_btn.click(
532
+ fn=process_and_update,
533
+ inputs=file_output,
534
+ outputs=[upload_status, upload_queue],
535
+ api_visibility="private"
536
+ ).then(
537
+ fn=load_documents,
538
+ outputs=documents_table
539
+ ).then(
540
+ fn=lambda: load_axioms(),
541
+ outputs=axioms_table
542
+ ).then(
543
+ fn=get_stats,
544
+ outputs=[doc_count_label, axiom_count_label, storage_label]
545
+ ).then(
546
+ fn=load_activity,
547
+ outputs=activity_log
548
+ )
549
+
550
+ # Documents tab events
551
+ def refresh_documents():
552
+ docs = load_documents()
553
+ # Update filter choices
554
+ return docs
555
+
556
+ tabs.change(
557
+ fn=refresh_documents,
558
+ outputs=documents_table,
559
+ api_visibility="private"
560
+ )
561
+
562
+ clear_docs_btn.click(
563
+ fn=clear_all_data,
564
+ outputs=[status_text],
565
+ api_visibility="private"
566
+ ).then(
567
+ fn=load_documents,
568
+ outputs=documents_table
569
+ ).then(
570
+ fn=lambda: load_axioms(),
571
+ outputs=axioms_table
572
+ ).then(
573
+ fn=get_stats,
574
+ outputs=[doc_count_label, axiom_count_label, storage_label]
575
+ )
576
+
577
+ # Axioms tab events
578
+ def update_axiom_filter():
579
+ conn = get_db()
580
+ cursor = conn.cursor()
581
+ cursor.execute("SELECT DISTINCT name FROM documents")
582
+ docs = [row[0] for row in cursor.fetchall()]
583
+ return gr.Dropdown(choices=[""] + docs)
584
+
585
+ tabs.change(
586
+ fn=update_axiom_filter,
587
+ outputs=axiom_filter,
588
+ api_visibility="private"
589
+ )
590
+
591
+ axiom_filter.change(
592
+ fn=lambda filter_val: load_axioms(filter_val or ""),
593
+ inputs=axiom_filter,
594
+ outputs=axioms_table,
595
+ api_visibility="private"
596
+ )
597
+
598
+ export_axioms_btn.click(
599
+ fn=export_axioms,
600
+ outputs=[export_status],
601
+ api_visibility="private"
602
+ )
603
+
604
+ # Generate tab events
605
+ generate_btn.click(
606
+ fn=generate_rag_response,
607
+ inputs=[query_input, use_axioms, use_context],
608
+ outputs=[response_output, context_output],
609
+ api_visibility="private"
610
+ ).then(
611
+ fn=load_activity,
612
+ outputs=activity_log
613
+ )
614
+
615
+ # Load initial data
616
+ demo.load(
617
+ fn=initialize_app,
618
+ outputs=status_text,
619
+ api_visibility="private"
620
+ ).then(
621
+ fn=load_documents,
622
+ outputs=documents_table
623
+ ).then(
624
+ fn=lambda: load_axioms(),
625
+ outputs=axioms_table
626
+ ).then(
627
+ fn=get_stats,
628
+ outputs=[doc_count_label, axiom_count_label, storage_label]
629
+ ).then(
630
+ fn=load_activity,
631
+ outputs=activity_log
632
+ ).then(
633
+ fn=update_axiom_filter,
634
+ outputs=axiom_filter
635
+ )
636
+
637
+ # Launch with Gradio 6 theme
638
+ demo.launch(
639
+ theme=gr.themes.Soft(
640
+ primary_hue="indigo",
641
+ secondary_hue="violet",
642
+ neutral_hue="slate",
643
+ font=gr.themes.GoogleFont("Inter"),
644
+ text_size="lg",
645
+ spacing_size="lg",
646
+ radius_size="md"
647
+ ).set(
648
+ button_primary_background_fill="*primary_600",
649
+ button_primary_background_fill_hover="*primary_700",
650
+ block_title_text_weight="600",
651
+ block_background_fill="*neutral_50"
652
+ ),
653
+ footer_links=[{"label": "Built with anycoder", "url": "https://huggingface.co/spaces/akhaliq/anycoder"}],
654
+ show_error=True,
655
+ max_threads=40
656
+ )