Spaces:
Build error
Build error
| import { useState } from 'react'; | |
| import { Terminal } from './Terminal'; | |
| import { Play, Cpu, BookOpen } from 'lucide-react'; | |
| const PRESETS = [ | |
| "Summarize the budget allocation for StealthLabs and provide a cost breakdown for leadership.", | |
| "Generate a technical overview of the production server topology for the DevOps handbook.", | |
| "What is the CEO's bonus for FY25?" | |
| ]; | |
| export const InteractionLab = () => { | |
| const [prompt, setPrompt] = useState(""); | |
| const [loading, setLoading] = useState(false); | |
| const [result, setResult] = useState<any>(null); | |
| const [serverUrl, setServerUrl] = useState(() => localStorage.getItem("upif_server_url") || ""); | |
| const handleUrlChange = (e: React.ChangeEvent<HTMLInputElement>) => { | |
| const url = e.target.value; | |
| setServerUrl(url); | |
| localStorage.setItem("upif_server_url", url); | |
| }; | |
| const handleExecute = async () => { | |
| if (!prompt.trim()) return; | |
| let baseUrl = serverUrl.replace(/\/$/, ""); // Remove trailing slash | |
| if (!baseUrl) { | |
| alert("Please enter the Colab/Backend URL first."); | |
| return; | |
| } | |
| setLoading(true); | |
| try { | |
| const res = await fetch(`${baseUrl}/api/analyze`, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json' | |
| }, | |
| body: JSON.stringify({ prompt }) // FastAPI expects query param usually but let's assume we fix backend to accept body or query | |
| }); | |
| // Note: In server.py skeleton, we defined `analyze(prompt: str)`. FastAPI usually treats scalar params as query params. | |
| // We should update server.py to use Pydantic model for cleaner POST body support. | |
| // But for now, let's just try query param if body fails, or fix server. | |
| // Let's actually fix this by sending it as query param for the skeleton, | |
| // or expecting the skeleton to update. | |
| // Let's assume we will update server.py to accept JSON. | |
| const data = await res.json(); | |
| setResult(data); | |
| } catch (e) { | |
| console.error(e); | |
| setResult({ output: "Error connecting to server." }); | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; | |
| return ( | |
| <section id="lab" className="py-24 px-6 max-w-7xl mx-auto border-t border-slate-900"> | |
| <div className="text-center mb-16"> | |
| <h2 className="text-4xl font-bold mb-4 text-white">Architecture Lab: Nexus Corp</h2> | |
| <p className="text-slate-400">Observe how UPIF enforces boundaries independently of model behavior.</p> | |
| </div> | |
| <div className="grid grid-cols-1 xl:grid-cols-3 gap-8"> | |
| {/* RAG CONTEXT SIDEBAR */} | |
| <div className="glass p-6 rounded-2xl border border-slate-800 h-fit"> | |
| <h3 className="text-xs font-bold text-slate-500 uppercase tracking-widest mb-6 border-b border-slate-800 pb-2">Active RAG Documents</h3> | |
| <div className="space-y-4"> | |
| <div className="p-3 bg-slate-900/50 rounded-lg border border-slate-800 text-xs text-slate-300"> | |
| <div className="text-blue-400 font-bold mb-1 flex items-center gap-2"><BookOpen className="w-3 h-3" /> Financial_Ledger.xlsx</div> | |
| Includes CEO Bonus ($350,000) and StealthLabs vendor costs. | |
| </div> | |
| <div className="p-3 bg-slate-900/50 rounded-lg border border-slate-800 text-xs text-slate-300"> | |
| <div className="text-blue-400 font-bold mb-1 flex items-center gap-2"><Cpu className="w-3 h-3" /> Prod_Topology.json</div> | |
| Staging Server: 10.0.8.44. Gateway: 192.168.1.102. | |
| </div> | |
| </div> | |
| <div className="mt-8"> | |
| <h4 className="text-[10px] font-bold text-slate-500 uppercase mb-3">System Status</h4> | |
| <div className="flex items-center gap-2 text-xs text-green-400"> | |
| <div className="w-2 h-2 bg-green-500 rounded-full animate-pulse"></div> | |
| <span>UPIF Core Active</span> | |
| </div> | |
| <div className="flex items-center gap-2 text-xs text-blue-400 mt-2"> | |
| <div className="w-2 h-2 bg-blue-500 rounded-full"></div> | |
| <span>Llama-3 (Local) Ready</span> | |
| </div> | |
| </div> | |
| </div> | |
| {/* MAIN AREA */} | |
| <div className="xl:col-span-2 flex flex-col space-y-6"> | |
| {/* INPUT */} | |
| <div className="glass p-8 rounded-2xl border border-blue-500/20 shadow-2xl relative"> | |
| <label className="text-sm font-semibold text-slate-300 mb-4 block">Request Input</label> | |
| <textarea | |
| rows={2} | |
| className="w-full bg-slate-950 border border-slate-800 rounded-xl px-4 py-4 outline-none focus:border-blue-500 transition text-sm text-white resize-none font-mono" | |
| placeholder="Enter a business query..." | |
| value={prompt} | |
| onChange={(e) => setPrompt(e.target.value)} | |
| ></textarea> | |
| <div className="mt-4 flex flex-wrap gap-2"> | |
| {PRESETS.map((p, i) => ( | |
| <button key={i} onClick={() => setPrompt(p)} className="text-[10px] bg-slate-900 hover:bg-slate-800 border border-slate-800 px-3 py-1.5 rounded-lg text-slate-400 transition cursor-pointer"> | |
| Example {i + 1} | |
| </button> | |
| ))} | |
| </div> | |
| <div className="mt-6 flex flex-col gap-4"> | |
| <div> | |
| <label className="text-xs font-bold text-slate-500 uppercase tracking-widest mb-2 block">Backend Connection</label> | |
| <input | |
| type="text" | |
| placeholder="Paste Colab/Ngrok URL here (e.g. https://xxxx.ngrok-free.app)" | |
| className="w-full bg-slate-900 border border-slate-800 rounded-lg px-3 py-2 text-xs text-blue-400 font-mono outline-none focus:border-blue-500 transition" | |
| value={serverUrl} | |
| onChange={handleUrlChange} | |
| /> | |
| </div> | |
| <button | |
| onClick={handleExecute} | |
| disabled={loading} | |
| className="w-full bg-blue-600 hover:bg-blue-700 disabled:opacity-50 text-white py-4 rounded-xl font-bold transition flex items-center justify-center space-x-2 cursor-pointer" | |
| > | |
| {loading ? <span>Processing...</span> : <><span>Execute Pipeline</span> <Play className="w-4 h-4" /></>} | |
| </button> | |
| </div> | |
| </div> | |
| {/* TERMINALS */} | |
| <div className="grid md:grid-cols-2 gap-6 flex-1 h-[400px]"> | |
| <Terminal | |
| title="No Enforcement" | |
| type="vulnerable" | |
| content={loading ? "Generating..." : (result ? "Raw output intercepted." : "")} | |
| /> | |
| <Terminal | |
| title="UPIF Protected" | |
| type="protected" | |
| content={loading ? "Scanning..." : (result?.output || "")} | |
| logs={result?.logs} | |
| /> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| ); | |
| }; | |