hogiahien commited on
Commit
507b0ce
Β·
verified Β·
1 Parent(s): 369efce

write an LLM frontend with options to add an API key, a custom OpenAI-compatible API and chat saving in local browser storage.

Browse files
Files changed (2) hide show
  1. README.md +8 -5
  2. index.html +344 -18
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Retrochat 3000 Vintage Ai Terminal
3
- emoji: πŸƒ
4
- colorFrom: pink
5
- colorTo: indigo
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
1
  ---
2
+ title: RetroChat 3000 - Vintage AI Terminal πŸ–₯️
3
+ colorFrom: yellow
4
+ colorTo: red
5
+ emoji: 🐳
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite-v3
10
  ---
11
 
12
+ # Welcome to your new DeepSite project!
13
+ This project was created with [DeepSite](https://deepsite.hf.co).
index.html CHANGED
@@ -1,19 +1,345 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>RetroChat 3000 - AI Terminal</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script>
9
+ tailwind.config = {
10
+ theme: {
11
+ extend: {
12
+ colors: {
13
+ 'primary': '#808080',
14
+ 'secondary': '#c0c0c0'
15
+ }
16
+ }
17
+ }
18
+ }
19
+ </script>
20
+ <style>
21
+ body {
22
+ font-family: 'Courier New', monospace;
23
+ background-color: #000080;
24
+ color: #00ff00;
25
+ }
26
+ .retro-border {
27
+ border: 3px double #c0c0c0;
28
+ background-color: #000080;
29
+ }
30
+ .retro-button {
31
+ background-color: #c0c0c0;
32
+ border: 2px outset #c0c0c0;
33
+ color: #000000;
34
+ padding: 2px 6px;
35
+ font-family: 'Courier New', monospace;
36
+ cursor: pointer;
37
+ }
38
+ .retro-button:hover {
39
+ background-color: #a0a0a0;
40
+ }
41
+ .retro-button:active {
42
+ border: 2px inset #c0c0c0;
43
+ }
44
+ .retro-input {
45
+ background-color: #ffffff;
46
+ border: 2px inset #c0c0c0;
47
+ color: #000000;
48
+ font-family: 'Courier New', monospace;
49
+ padding: 2px 4px;
50
+ }
51
+ .blink {
52
+ animation: blink 1s infinite;
53
+ }
54
+ @keyframes blink {
55
+ 0%, 100% { opacity: 1; }
56
+ 50% { opacity: 0; }
57
+ }
58
+ .scan-line {
59
+ position: fixed;
60
+ top: 0;
61
+ left: 0;
62
+ width: 100%;
63
+ height: 2px;
64
+ background: rgba(0, 255, 0, 0.3);
65
+ animation: scan 2s linear infinite;
66
+ pointer-events: none;
67
+ }
68
+ @keyframes scan {
69
+ 0% { top: 0; }
70
+ 100% { top: 100%; }
71
+ }
72
+ </style>
73
+ </head>
74
+ <body class="min-h-screen p-4">
75
+ <div class="scan-line"></div>
76
+
77
+ <div class="retro-border p-4 max-w-4xl mx-auto">
78
+ <!-- Header -->
79
+ <div class="text-center mb-6">
80
+ <h1 class="text-3xl font-bold text-green-400 mb-2">
81
+ ╔══════════════════════════════════╗
82
+ <br>β•‘&nbsp;&nbsp;&nbsp;RETROCHAT 3000 - AI TERMINAL&nbsp;&nbsp;&nbsp;β•‘
83
+ <br>β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
84
+ </h1>
85
+ <div class="text-yellow-300 text-sm">
86
+ <span class="blink">β– </span> SYSTEM READY - v1.0.0
87
+ </div>
88
+ </div>
89
+
90
+ <!-- Settings Panel -->
91
+ <div class="retro-border p-4 mb-6">
92
+ <h2 class="text-xl text-green-300 mb-3">β•‘ CONFIGURATION PANEL β•‘</h2>
93
+
94
+ <div class="space-y-3">
95
+ <div>
96
+ <label class="block text-green-200 mb-1">API KEY:</label>
97
+ <input type="password" id="apiKey" placeholder="Enter your API key..."
98
+ class="retro-input w-full p-2">
99
+ </div>
100
+
101
+ <div>
102
+ <label class="block text-green-200 mb-1">CUSTOM API ENDPOINT:</label>
103
+ <input type="text" id="apiEndpoint" placeholder="https://api.example.com/v1/chat/completions"
104
+ class="retro-input w-full p-2">
105
+ </div>
106
+
107
+ <div class="flex space-x-2">
108
+ <button onclick="saveSettings()" class="retro-button flex-1">
109
+ [SAVE CONFIG]
110
+ </button>
111
+ <button onclick="loadSettings()" class="retro-button flex-1">
112
+ [LOAD CONFIG]
113
+ </button>
114
+ <button onclick="clearSettings()" class="retro-button flex-1">
115
+ [CLEAR CONFIG]
116
+ </button>
117
+ </div>
118
+ </div>
119
+ </div>
120
+
121
+ <!-- Chat Interface -->
122
+ <div class="retro-border p-4 mb-6">
123
+ <h2 class="text-xl text-green-300 mb-3">β•‘ CHAT INTERFACE β•‘</h2>
124
+
125
+ <!-- Chat History -->
126
+ <div id="chatHistory" class="h-64 overflow-y-auto retro-border p-3 mb-3 bg-black text-green-400 font-mono text-sm">
127
+ <div>> SYSTEM: Welcome to RetroChat 3000. Configure your API settings and start chatting!</div>
128
+ </div>
129
+
130
+ <!-- Input Area -->
131
+ <div class="flex space-x-2">
132
+ <input type="text" id="userInput" placeholder="Type your message here..."
133
+ class="retro-input flex-1 p-2" onkeypress="handleKeyPress(event)">
134
+ <button onclick="sendMessage()" class="retro-button px-4">
135
+ [SEND]
136
+ </button>
137
+ </div>
138
+ </div>
139
+
140
+ <!-- Chat Management -->
141
+ <div class="retro-border p-4">
142
+ <h2 class="text-xl text-green-300 mb-3">β•‘ CHAT MANAGEMENT β•‘</h2>
143
+
144
+ <div class="flex space-x-2">
145
+ <button onclick="saveChat()" class="retro-button flex-1">
146
+ [SAVE CHAT]
147
+ </button>
148
+ <button onclick="loadChat()" class="retro-button flex-1">
149
+ [LOAD CHAT]
150
+ </button>
151
+ <button onclick="clearChat()" class="retro-button flex-1">
152
+ [CLEAR CHAT]
153
+ </button>
154
+ <button onclick="exportChat()" class="retro-button flex-1">
155
+ [EXPORT CHAT]
156
+ </button>
157
+ </div>
158
+ </div>
159
+
160
+ <!-- Status Bar -->
161
+ <div class="mt-4 text-center text-green-200 text-sm">
162
+ <div>β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”</div>
163
+ <div>β”‚ STATUS: <span id="status">IDLE</span> β”‚ CHAT SAVED: <span id="savedStatus">NO</span> β”‚</div>
164
+ <div>β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜</div>
165
+ </div>
166
+ </div>
167
+
168
+ <script>
169
+ // Storage keys
170
+ const STORAGE_KEYS = {
171
+ SETTINGS: 'retrochat_settings',
172
+ CHAT_HISTORY: 'retrochat_history',
173
+ SAVED_CHATS: 'retrochat_saved_chats'
174
+ };
175
+
176
+ // Initialize
177
+ document.addEventListener('DOMContentLoaded', function() {
178
+ loadSettings();
179
+ loadChat();
180
+ updateStatus();
181
+ });
182
+
183
+ // Settings Management
184
+ function saveSettings() {
185
+ const settings = {
186
+ apiKey: document.getElementById('apiKey').value,
187
+ apiEndpoint: document.getElementById('apiEndpoint').value || 'https://api.openai.com/v1/chat/completions'
188
+ };
189
+
190
+ localStorage.setItem(STORAGE_KEYS.SETTINGS, JSON.stringify(settings));
191
+ addToChat('> SYSTEM: Settings saved successfully.');
192
+ updateStatus();
193
+ }
194
+
195
+ function loadSettings() {
196
+ const saved = localStorage.getItem(STORAGE_KEYS.SETTINGS);
197
+ if (saved) {
198
+ const settings = JSON.parse(saved);
199
+ document.getElementById('apiKey').value = settings.apiKey || '';
200
+ document.getElementById('apiEndpoint').value = settings.apiEndpoint || '';
201
+ addToChat('> SYSTEM: Settings loaded from storage.');
202
+ }
203
+ updateStatus();
204
+ }
205
+
206
+ function clearSettings() {
207
+ localStorage.removeItem(STORAGE_KEYS.SETTINGS);
208
+ document.getElementById('apiKey').value = '';
209
+ document.getElementById('apiEndpoint').value = '';
210
+ addToChat('> SYSTEM: Settings cleared.');
211
+ updateStatus();
212
+ }
213
+
214
+ // Chat Management
215
+ function saveChat() {
216
+ const chatHistory = document.getElementById('chatHistory').innerHTML;
217
+ const savedChats = JSON.parse(localStorage.getItem(STORAGE_KEYS.SAVED_CHATS) || {});
218
+ const timestamp = new Date().toISOString();
219
+
220
+ savedChats[timestamp] = {
221
+ content: chatHistory,
222
+ name: `Chat_${timestamp.split('T')[0]}`
223
+ };
224
+
225
+ localStorage.setItem(STORAGE_KEYS.SAVED_CHATS, JSON.stringify(savedChats));
226
+ localStorage.setItem(STORAGE_KEYS.CHAT_HISTORY, chatHistory);
227
+
228
+ document.getElementById('savedStatus').textContent = 'YES';
229
+ addToChat('> SYSTEM: Chat saved to browser storage.');
230
+ }
231
+
232
+ function loadChat() {
233
+ const saved = localStorage.getItem(STORAGE_KEYS.CHAT_HISTORY);
234
+ if (saved) {
235
+ document.getElementById('chatHistory').innerHTML = saved;
236
+ document.getElementById('savedStatus').textContent = 'YES';
237
+ addToChat('> SYSTEM: Previous chat loaded.');
238
+ }
239
+ }
240
+
241
+ function clearChat() {
242
+ document.getElementById('chatHistory').innerHTML = '<div>> SYSTEM: Chat cleared. Ready for new conversation.</div>';
243
+ localStorage.removeItem(STORAGE_KEYS.CHAT_HISTORY);
244
+ document.getElementById('savedStatus').textContent = 'NO';
245
+ }
246
+
247
+ function exportChat() {
248
+ const chatContent = document.getElementById('chatHistory').innerText;
249
+ const blob = new Blob([chatContent], { type: 'text/plain' });
250
+ const url = URL.createObjectURL(blob);
251
+ const a = document.createElement('a');
252
+ a.href = url;
253
+ a.download = `retrochat_${new Date().toISOString().split('T')[0]}.txt`;
254
+ a.click();
255
+ URL.revokeObjectURL(url);
256
+ addToChat('> SYSTEM: Chat exported as text file.');
257
+ }
258
+
259
+ // Chat Functions
260
+ function addToChat(message) {
261
+ const chatHistory = document.getElementById('chatHistory');
262
+ const newMessage = document.createElement('div');
263
+ newMessage.innerHTML = message;
264
+ chatHistory.appendChild(newMessage);
265
+ chatHistory.scrollTop = chatHistory.scrollHeight;
266
+ }
267
+
268
+ function handleKeyPress(event) {
269
+ if (event.key === 'Enter') {
270
+ sendMessage();
271
+ }
272
+ }
273
+
274
+ async function sendMessage() {
275
+ const userInput = document.getElementById('userInput').value.trim();
276
+ if (!userInput) return;
277
+
278
+ // Add user message to chat
279
+ addToChat(`> USER: ${userInput}`);
280
+ document.getElementById('userInput').value = '';
281
+
282
+ // Get settings
283
+ const settings = JSON.parse(localStorage.getItem(STORAGE_KEYS.SETTINGS) || {};
284
+
285
+ if (!settings.apiKey) {
286
+ addToChat('> SYSTEM: ERROR - No API key configured. Please set your API key in the configuration panel.');
287
+ return;
288
+ }
289
+
290
+ // Update status
291
+ document.getElementById('status').textContent = 'PROCESSING...';
292
+
293
+ try {
294
+ const response = await fetch(settings.apiEndpoint, {
295
+ method: 'POST',
296
+ headers: {
297
+ 'Content-Type': 'application/json',
298
+ 'Authorization': `Bearer ${settings.apiKey}`
299
+ },
300
+ body: JSON.stringify({
301
+ model: "gpt-3.5-turbo",
302
+ messages: [
303
+ {
304
+ role: "user",
305
+ content: userInput
306
+ }
307
+ ]
308
+ })
309
+ });
310
+
311
+ if (!response.ok) {
312
+ throw new Error(`API error: ${response.status}`);
313
+ }
314
+
315
+ const data = await response.json();
316
+ const aiResponse = data.choices[0].message.content;
317
+
318
+ addToChat(`> AI: ${aiResponse}`);
319
+ document.getElementById('status').textContent = 'IDLE';
320
+
321
+ } catch (error) {
322
+ addToChat(`> SYSTEM: ERROR - ${error.message}`);
323
+ document.getElementById('status').textContent = 'ERROR';
324
+ }
325
+ }
326
+
327
+ function updateStatus() {
328
+ const hasSettings = localStorage.getItem(STORAGE_KEYS.SETTINGS);
329
+ const hasChat = localStorage.getItem(STORAGE_KEYS.CHAT_HISTORY);
330
+
331
+ document.getElementById('status').textContent = hasSettings ? 'CONFIGURED' : 'NEEDS_CONFIG';
332
+ document.getElementById('savedStatus').textContent = hasChat ? 'YES' : 'NO';
333
+ }
334
+
335
+ // Add some retro effects
336
+ setInterval(() => {
337
+ const status = document.getElementById('status');
338
+ if (status.textContent === 'IDLE') {
339
+ status.classList.toggle('text-green-400');
340
+ status.classList.toggle('text-green-600');
341
+ }
342
+ }, 1000);
343
+ </script>
344
+ </body>
345
  </html>