File size: 3,082 Bytes
9f3f336
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import React, { useEffect, useState } from 'react';

export default function App() {
  const [browserFrame, setBrowserFrame] = useState<string>("");
  const [logs, setLogs] = useState<string[]>([]);
  const [input, setInput] = useState("");

  useEffect(() => {
    const eventSource = new EventSource("/api/stream");
    eventSource.onmessage = (event) => {
      try {
        const data = JSON.parse(event.data);
        if (data.type === "frame") setBrowserFrame(data.data);
        if (data.type === "log") setLogs(prev => [...prev, data.data].slice(-10));
      } catch (e) {
        console.error("SSE Parse Error", e);
      }
    };
    return () => eventSource.close();
  }, []);

  const sendMessage = async () => {
    if (!input) return;
    setLogs(prev => [...prev, `You: ${input}`]);
    await fetch("/api/chat", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ message: input })
    });
    setInput("");
  };

  return (
    <div className="flex h-screen bg-zinc-950 text-zinc-200 font-sans">
      <div className="w-80 flex flex-col border-r border-zinc-800 p-4 bg-zinc-900/50">
        <h1 className="text-lg font-bold mb-4 text-blue-500 flex items-center gap-2">
          <div className="w-3 h-3 bg-blue-500 rounded-full animate-pulse"></div>
          Polymorphic Agent
        </h1>
        <div className="flex-1 overflow-y-auto space-y-2 mb-4 scrollbar-hide">
          {logs.map((log, i) => (
            <div key={i} className="p-2 bg-zinc-800/50 rounded border border-zinc-700/50 text-xs">
              {log}
            </div>
          ))}
        </div>
        <div className="flex gap-2">
          <input 
            className="flex-1 bg-zinc-800 border border-zinc-700 p-2 rounded text-sm focus:outline-none focus:border-blue-500"
            value={input}
            onChange={(e) => setInput(e.target.value)}
            onKeyDown={(e) => e.key === 'Enter' && sendMessage()}
            placeholder="Ask agent..."
          />
          <button onClick={sendMessage} className="bg-blue-600 hover:bg-blue-500 px-3 py-1 rounded text-sm transition-colors">
            Send
          </button>
        </div>
      </div>

      <div className="flex-1 bg-black flex flex-col relative">
        <div className="absolute top-2 left-2 z-10 bg-black/60 px-2 py-1 rounded text-[10px] uppercase tracking-widest text-zinc-500 border border-zinc-800">
          Live Nix Environment View
        </div>
        <div className="flex-1 flex items-center justify-center">
          {browserFrame ? (
            <img src={`data:image/jpeg;base64,${browserFrame}`} className="max-w-full max-h-full object-contain shadow-2xl" />
          ) : (
            <div className="flex flex-col items-center gap-3">
              <div className="w-8 h-8 border-4 border-blue-500/20 border-t-blue-500 rounded-full animate-spin"></div>
              <div className="text-zinc-600 text-sm font-medium">Initializing Browser...</div>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}