File size: 4,102 Bytes
7f69ad8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import React, { useState, useEffect } from 'react';
const { ipcRenderer } = window.require('electron');

export default function App() {
  const [messages, setMessages] = useState([]);
  const [input, setInput] = useState("");
  const [memoryActive, setMemoryActive] = useState(false);
  const [models, setModels] = useState({ local: [], presets: [] });
  const [selectedModel, setSelectedModel] = useState("ibm-granite/granite-3.0-2b-instruct");

  useEffect(() => {
    // Initial Load
    ipcRenderer.send('list-models');
    
    ipcRenderer.on('model-list', (e, data) => setModels(data));
    
    ipcRenderer.on('receive-token', (event, token) => {
      setMessages(prev => {
        const last = prev[prev.length - 1];
        if (last && last.role === 'assistant') {
          return [...prev.slice(0, -1), { role: 'assistant', text: last.text + token }];
        }
        return [...prev, { role: 'assistant', text: token }];
      });
    });
    
    ipcRenderer.on('stream-end', () => setMemoryActive(false));
  }, []);

  const sendMessage = () => {
    if (!input) return;
    setMessages(prev => [...prev, { role: 'user', text: input }]);
    ipcRenderer.send('send-message', { model: selectedModel, text: input });
    setInput("");
    setMemoryActive(true);
  };

  return (
    <div style={{ display: 'flex', height: '100vh', background: '#1e1e1e', color: 'white' }}>
      
      {/* LEFT: Chat Panel */}
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', borderRight: '1px solid #333' }}>
        <div style={{ padding: 20, borderBottom: '1px solid #333', display: 'flex', justifyContent: 'space-between' }}>
          <h2>🪔 OV-Studio</h2>
          <select 
            value={selectedModel} 
            onChange={e => setSelectedModel(e.target.value)}
            style={{ background: '#333', color: 'white', padding: 5, borderRadius: 5 }}
          >
            <optgroup label="Preset Models">
                {models.presets.map(m => <option key={m} value={m}>{m}</option>)}
            </optgroup>
            <optgroup label="Local GGUF">
                {models.local.map(m => <option key={m} value={m}>{m}</option>)}
            </optgroup>
          </select>
        </div>
        
        <div style={{ flex: 1, padding: 20, overflowY: 'auto' }}>
          {messages.map((m, i) => (
            <div key={i} style={{ 
              marginBottom: 15, 
              alignSelf: m.role === 'user' ? 'flex-end' : 'flex-start',
              background: m.role === 'user' ? '#007acc' : '#333',
              padding: 10, borderRadius: 10, maxWidth: '80%' 
            }}>
              <strong>{m.role === 'user' ? 'You' : 'OV-Engine'}:</strong>
              <p style={{ margin: '5px 0 0 0' }}>{m.text}</p>
            </div>
          ))}
        </div>

        <div style={{ padding: 20, background: '#252526' }}>
          <input 
            value={input}
            onChange={e => setInput(e.target.value)}
            onKeyPress={e => e.key === 'Enter' && sendMessage()}
            placeholder="Ask OV-Engine..."
            style={{ width: '100%', padding: 10, borderRadius: 5, border: 'none' }} 
          />
        </div>
      </div>

      {/* RIGHT: Memory Visualizer (Honeycomb) */}
      <div style={{ width: 400, background: '#111', padding: 20 }}>
        <h3>🕸️ Memory Graph</h3>
        <p>Status: {memoryActive ? "Scanning C++ Kernel..." : "Idle"}</p>
        
        {/* Placeholder for 3D Graph */}
        <div style={{ 
          marginTop: 20, height: 300, 
          background: memoryActive ? '#004400' : '#222', 
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          transition: 'background 0.5s'
        }}>
          {memoryActive ? "Searching 20,000 Vectors..." : "Waiting for Query"}
        </div>
        
        <div style={{ marginTop: 20 }}>
          <h4>Active Context:</h4>
          <div style={{ fontSize: 12, color: '#aaa' }}>
            {memoryActive ? "Calculating P = S * C * R * W" : "None"}
          </div>
        </div>
      </div>

    </div>
  );
}