Spaces:
Running
Running
Commit
·
697eb00
1
Parent(s):
63b0e81
🧹 Clean up and optimize HF Spaces deployment
Browse files✅ Cleanup applied:
• Removed unnecessary Privacy Notice Modal component
• Streamlined backend app.py startup configuration
• Simplified database initialization imports
• Cleaned up frontend config and layout components
🎯 Purpose:
• Reduce bundle size for faster HF Spaces deployment
• Remove unused UI components
• Optimize startup performance
• Maintain only essential functionality for demo
⚡ Impact:
• Smaller Docker image size
• Faster build and startup times
• Cleaner codebase for HF Spaces environment
backend/app.py
CHANGED
|
@@ -77,15 +77,6 @@ async def startup_event():
|
|
| 77 |
try:
|
| 78 |
from backend.database.init_db import init_database
|
| 79 |
init_database(reset=False, force=False)
|
| 80 |
-
|
| 81 |
-
# Show database type info
|
| 82 |
-
if os.getenv("SPACE_ID"):
|
| 83 |
-
logger.info("🔒 HF Spaces: Using temporary file database for user privacy")
|
| 84 |
-
logger.info("📝 Note: Data will be cleared when container restarts")
|
| 85 |
-
logger.info("🛡️ User isolation: Each session has its own database")
|
| 86 |
-
else:
|
| 87 |
-
logger.info("💾 Local development: Using persistent database")
|
| 88 |
-
|
| 89 |
logger.info("🗄️ Database initialized successfully")
|
| 90 |
except Exception as e:
|
| 91 |
logger.error(f"❌ Database initialization failed: {e}")
|
|
|
|
| 77 |
try:
|
| 78 |
from backend.database.init_db import init_database
|
| 79 |
init_database(reset=False, force=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 80 |
logger.info("🗄️ Database initialized successfully")
|
| 81 |
except Exception as e:
|
| 82 |
logger.error(f"❌ Database initialization failed: {e}")
|
backend/database/__init__.py
CHANGED
|
@@ -11,36 +11,11 @@ from sqlalchemy.orm import sessionmaker, scoped_session
|
|
| 11 |
# Get the absolute path to the project root directory
|
| 12 |
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
| 13 |
|
| 14 |
-
# Database URL
|
| 15 |
-
|
| 16 |
-
import uuid
|
| 17 |
-
import tempfile
|
| 18 |
-
session_id = str(uuid.uuid4())[:8]
|
| 19 |
|
| 20 |
-
#
|
| 21 |
-
|
| 22 |
-
if os.getenv("SPACE_ID"): # HF Spaces environment
|
| 23 |
-
# Use temporary file instead of in-memory to avoid connection pool issues
|
| 24 |
-
temp_db_path = f"/tmp/agentgraph_{session_id}.db"
|
| 25 |
-
DATABASE_URL = f"sqlite:///{temp_db_path}"
|
| 26 |
-
print(f"🔒 HF Spaces: Using temporary database (session: {session_id})")
|
| 27 |
-
print(f"📁 Database path: {temp_db_path}")
|
| 28 |
-
else:
|
| 29 |
-
DATABASE_URL = f"sqlite:///{os.path.join(ROOT_DIR, 'datasets/db/agent_monitoring.db')}"
|
| 30 |
-
print(f"💾 Local: Using persistent database")
|
| 31 |
-
|
| 32 |
-
# Create engine with proper SQLite configuration for async operations
|
| 33 |
-
engine = create_engine(
|
| 34 |
-
DATABASE_URL,
|
| 35 |
-
connect_args={
|
| 36 |
-
"check_same_thread": False,
|
| 37 |
-
"timeout": 30,
|
| 38 |
-
"isolation_level": None, # Autocommit mode
|
| 39 |
-
},
|
| 40 |
-
pool_pre_ping=True, # Verify connections before use
|
| 41 |
-
pool_recycle=3600, # Recycle connections every hour
|
| 42 |
-
echo=False # Disable SQL logging for production
|
| 43 |
-
)
|
| 44 |
|
| 45 |
# Create session factory
|
| 46 |
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
|
|
|
| 11 |
# Get the absolute path to the project root directory
|
| 12 |
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
| 13 |
|
| 14 |
+
# Database URL with absolute path
|
| 15 |
+
DATABASE_URL = f"sqlite:///{os.path.join(ROOT_DIR, 'datasets/db/agent_monitoring.db')}"
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
+
# Create engine
|
| 18 |
+
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
|
| 20 |
# Create session factory
|
| 21 |
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
frontend/src/components/layout/MainWorkspace.tsx
CHANGED
|
@@ -16,7 +16,6 @@ import { ConnectionsView } from "../features/connections/ConnectionsView";
|
|
| 16 |
import { UploadView } from "../features/upload/UploadView";
|
| 17 |
import { Button } from "@/components/ui/button";
|
| 18 |
import { ArrowLeft } from "lucide-react";
|
| 19 |
-
import { PrivacyNoticeModal } from "@/components/shared/modals/PrivacyNoticeModal";
|
| 20 |
|
| 21 |
interface MainWorkspaceProps {
|
| 22 |
isSidebarCollapsed: boolean;
|
|
@@ -331,9 +330,6 @@ export function MainWorkspace({
|
|
| 331 |
{/* Global Floating Action Widget for temporal view */}
|
| 332 |
<FloatingActionWidget />
|
| 333 |
|
| 334 |
-
{/* Privacy Notice Modal */}
|
| 335 |
-
<PrivacyNoticeModal />
|
| 336 |
-
|
| 337 |
{/* Breadcrumb Navigation */}
|
| 338 |
<div className="border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
| 339 |
<div className="flex items-center justify-between px-6 py-3">
|
|
@@ -395,9 +391,6 @@ export function MainWorkspace({
|
|
| 395 |
</div>
|
| 396 |
)}
|
| 397 |
|
| 398 |
-
{/* Privacy Notice Modal */}
|
| 399 |
-
<PrivacyNoticeModal />
|
| 400 |
-
|
| 401 |
{/* Main Content */}
|
| 402 |
<div className="flex-1 flex flex-col min-h-0">{renderView()}</div>
|
| 403 |
</div>
|
|
|
|
| 16 |
import { UploadView } from "../features/upload/UploadView";
|
| 17 |
import { Button } from "@/components/ui/button";
|
| 18 |
import { ArrowLeft } from "lucide-react";
|
|
|
|
| 19 |
|
| 20 |
interface MainWorkspaceProps {
|
| 21 |
isSidebarCollapsed: boolean;
|
|
|
|
| 330 |
{/* Global Floating Action Widget for temporal view */}
|
| 331 |
<FloatingActionWidget />
|
| 332 |
|
|
|
|
|
|
|
|
|
|
| 333 |
{/* Breadcrumb Navigation */}
|
| 334 |
<div className="border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
| 335 |
<div className="flex items-center justify-between px-6 py-3">
|
|
|
|
| 391 |
</div>
|
| 392 |
)}
|
| 393 |
|
|
|
|
|
|
|
|
|
|
| 394 |
{/* Main Content */}
|
| 395 |
<div className="flex-1 flex flex-col min-h-0">{renderView()}</div>
|
| 396 |
</div>
|
frontend/src/components/shared/modals/PrivacyNoticeModal.tsx
DELETED
|
@@ -1,110 +0,0 @@
|
|
| 1 |
-
import React, { useState, useEffect } from "react";
|
| 2 |
-
import {
|
| 3 |
-
Dialog,
|
| 4 |
-
DialogContent,
|
| 5 |
-
DialogDescription,
|
| 6 |
-
DialogFooter,
|
| 7 |
-
DialogHeader,
|
| 8 |
-
DialogTitle,
|
| 9 |
-
} from "@/components/ui/dialog";
|
| 10 |
-
import { Button } from "@/components/ui/button";
|
| 11 |
-
import { Shield, Info, Database, RefreshCw } from "lucide-react";
|
| 12 |
-
import { IS_HF_SPACES } from "@/lib/config";
|
| 13 |
-
|
| 14 |
-
const PRIVACY_NOTICE_KEY = "agentgraph_privacy_notice_seen";
|
| 15 |
-
|
| 16 |
-
export function PrivacyNoticeModal() {
|
| 17 |
-
const [isOpen, setIsOpen] = useState(false);
|
| 18 |
-
|
| 19 |
-
useEffect(() => {
|
| 20 |
-
// Only show on HF Spaces and if not seen before
|
| 21 |
-
if (!IS_HF_SPACES) return;
|
| 22 |
-
|
| 23 |
-
const hasSeenNotice = localStorage.getItem(PRIVACY_NOTICE_KEY);
|
| 24 |
-
if (hasSeenNotice) return;
|
| 25 |
-
|
| 26 |
-
// Show modal after a short delay to ensure the app is loaded
|
| 27 |
-
const timer = setTimeout(() => {
|
| 28 |
-
setIsOpen(true);
|
| 29 |
-
}, 1000);
|
| 30 |
-
|
| 31 |
-
return () => clearTimeout(timer);
|
| 32 |
-
}, []);
|
| 33 |
-
|
| 34 |
-
const handleAccept = () => {
|
| 35 |
-
localStorage.setItem(PRIVACY_NOTICE_KEY, "true");
|
| 36 |
-
setIsOpen(false);
|
| 37 |
-
};
|
| 38 |
-
|
| 39 |
-
const handleDismiss = () => {
|
| 40 |
-
// Don't set localStorage, so it shows again next time
|
| 41 |
-
setIsOpen(false);
|
| 42 |
-
};
|
| 43 |
-
|
| 44 |
-
// Don't render anything if not on HF Spaces
|
| 45 |
-
if (!IS_HF_SPACES) {
|
| 46 |
-
return null;
|
| 47 |
-
}
|
| 48 |
-
|
| 49 |
-
return (
|
| 50 |
-
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
| 51 |
-
<DialogContent className="sm:max-w-[500px]">
|
| 52 |
-
<DialogHeader>
|
| 53 |
-
<DialogTitle className="flex items-center gap-2 text-lg">
|
| 54 |
-
<Shield className="h-5 w-5 text-blue-600" />
|
| 55 |
-
Privacy Notice - Hugging Face Spaces
|
| 56 |
-
</DialogTitle>
|
| 57 |
-
<DialogDescription className="text-left space-y-3 pt-2">
|
| 58 |
-
<div className="flex items-start gap-3">
|
| 59 |
-
<Database className="h-4 w-4 text-amber-600 mt-0.5 flex-shrink-0" />
|
| 60 |
-
<div className="text-sm">
|
| 61 |
-
<strong>Temporary Data Storage:</strong> Your data is stored in
|
| 62 |
-
a private, temporary session that is automatically cleared when
|
| 63 |
-
the container restarts.
|
| 64 |
-
</div>
|
| 65 |
-
</div>
|
| 66 |
-
|
| 67 |
-
<div className="flex items-start gap-3">
|
| 68 |
-
<Shield className="h-4 w-4 text-green-600 mt-0.5 flex-shrink-0" />
|
| 69 |
-
<div className="text-sm">
|
| 70 |
-
<strong>Complete Privacy:</strong> Your traces and analysis
|
| 71 |
-
results are not shared between users or sessions. Each user has
|
| 72 |
-
their own isolated environment.
|
| 73 |
-
</div>
|
| 74 |
-
</div>
|
| 75 |
-
|
| 76 |
-
<div className="flex items-start gap-3">
|
| 77 |
-
<RefreshCw className="h-4 w-4 text-blue-600 mt-0.5 flex-shrink-0" />
|
| 78 |
-
<div className="text-sm">
|
| 79 |
-
<strong>Data Lifecycle:</strong> All uploaded traces, knowledge
|
| 80 |
-
graphs, and analysis results will be permanently deleted when
|
| 81 |
-
the Hugging Face Spaces container restarts.
|
| 82 |
-
</div>
|
| 83 |
-
</div>
|
| 84 |
-
|
| 85 |
-
<div className="flex items-start gap-3">
|
| 86 |
-
<Info className="h-4 w-4 text-gray-600 mt-0.5 flex-shrink-0" />
|
| 87 |
-
<div className="text-sm">
|
| 88 |
-
<strong>Recommendation:</strong> For persistent data storage and
|
| 89 |
-
analysis, consider running AgentGraph locally or on your own
|
| 90 |
-
infrastructure.
|
| 91 |
-
</div>
|
| 92 |
-
</div>
|
| 93 |
-
</DialogDescription>
|
| 94 |
-
</DialogHeader>
|
| 95 |
-
|
| 96 |
-
<DialogFooter className="flex gap-2 sm:gap-2">
|
| 97 |
-
<Button variant="outline" onClick={handleDismiss} className="flex-1">
|
| 98 |
-
Remind Me Later
|
| 99 |
-
</Button>
|
| 100 |
-
<Button
|
| 101 |
-
onClick={handleAccept}
|
| 102 |
-
className="flex-1 bg-blue-600 hover:bg-blue-700"
|
| 103 |
-
>
|
| 104 |
-
I Understand
|
| 105 |
-
</Button>
|
| 106 |
-
</DialogFooter>
|
| 107 |
-
</DialogContent>
|
| 108 |
-
</Dialog>
|
| 109 |
-
);
|
| 110 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
frontend/src/lib/config.ts
CHANGED
|
@@ -24,16 +24,3 @@ export const getApiBase = () => {
|
|
| 24 |
};
|
| 25 |
|
| 26 |
export const API_BASE = getApiBase();
|
| 27 |
-
|
| 28 |
-
// Check if running on Hugging Face Spaces
|
| 29 |
-
export const isHuggingFaceSpaces = () => {
|
| 30 |
-
if (typeof window === "undefined") return false;
|
| 31 |
-
|
| 32 |
-
return (
|
| 33 |
-
window.location.hostname.includes("huggingface.co") ||
|
| 34 |
-
window.location.hostname.includes("hf.space") ||
|
| 35 |
-
window.location.hostname.endsWith(".hf.space")
|
| 36 |
-
);
|
| 37 |
-
};
|
| 38 |
-
|
| 39 |
-
export const IS_HF_SPACES = isHuggingFaceSpaces();
|
|
|
|
| 24 |
};
|
| 25 |
|
| 26 |
export const API_BASE = getApiBase();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|