File size: 8,250 Bytes
b28041c
 
 
 
 
 
 
 
 
 
 
 
 
 
1b7ef07
 
 
 
 
 
 
b28041c
 
 
1b7ef07
 
 
 
 
 
 
b28041c
 
1b7ef07
b28041c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1b7ef07
 
 
 
 
 
 
 
 
 
 
 
b28041c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
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>
    );
};