marcodsn commited on
Commit
9eaf1c8
Β·
verified Β·
1 Parent(s): 26464c9

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +418 -17
index.html CHANGED
@@ -1,19 +1,420 @@
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>JSONL Conversation Visualizer</title>
7
+ <style>
8
+ /* --- Reset and Global Styles --- */
9
+ * {
10
+ margin: 0;
11
+ padding: 0;
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ html,
16
+ body {
17
+ font-family:
18
+ system-ui,
19
+ -apple-system,
20
+ sans-serif;
21
+ background: #fafafa;
22
+ line-height: 1.5;
23
+ color: #333;
24
+ /* Prevent the main page from scrolling */
25
+ height: 100%;
26
+ overflow: hidden;
27
+ }
28
+
29
+ /* --- Main Layout (Flexbox) --- */
30
+ .app-container {
31
+ display: flex;
32
+ height: 100vh; /* Full viewport height */
33
+ }
34
+
35
+ .sidebar {
36
+ width: 400px;
37
+ flex-shrink: 0; /* Prevent sidebar from shrinking */
38
+ background: #ffffff;
39
+ border-right: 1px solid #e0e0e0;
40
+ display: flex;
41
+ flex-direction: column;
42
+ overflow-y: auto; /* Allow sidebar to scroll if needed on small screens */
43
+ }
44
+
45
+ .main-content {
46
+ flex-grow: 1; /* Take up remaining space */
47
+ display: none; /* Hidden by default, shown by JS */
48
+ flex-direction: column;
49
+ }
50
+
51
+ /* --- Sidebar Components --- */
52
+ .input-section {
53
+ padding: 20px;
54
+ border-bottom: 1px solid #e0e0e0;
55
+ }
56
+
57
+ .input-section h1 {
58
+ margin-bottom: 12px;
59
+ font-size: 20px;
60
+ font-weight: 500;
61
+ }
62
+
63
+ #jsonInput {
64
+ width: 100%;
65
+ height: 120px;
66
+ padding: 10px;
67
+ border: 1px solid #ccc;
68
+ border-radius: 2px;
69
+ font-family: monospace;
70
+ font-size: 12px;
71
+ resize: vertical;
72
+ }
73
+
74
+ #parseBtn {
75
+ margin-top: 8px;
76
+ padding: 8px 16px;
77
+ background: #333;
78
+ color: white;
79
+ border: none;
80
+ border-radius: 2px;
81
+ cursor: pointer;
82
+ font-size: 13px;
83
+ }
84
+
85
+ #parseBtn:hover {
86
+ background: #555;
87
+ }
88
+
89
+ .error {
90
+ color: #d73a49;
91
+ margin-top: 8px;
92
+ font-size: 13px;
93
+ display: none;
94
+ }
95
+
96
+ .header-info {
97
+ padding: 20px;
98
+ display: none; /* Hidden by default */
99
+ }
100
+
101
+ .header-info h2 {
102
+ margin-bottom: 12px;
103
+ font-size: 16px;
104
+ font-weight: 500;
105
+ }
106
+
107
+ .situation-info {
108
+ margin-bottom: 16px;
109
+ font-size: 13px;
110
+ }
111
+
112
+ .situation-info p {
113
+ margin-bottom: 4px;
114
+ }
115
+
116
+ .personas {
117
+ display: grid;
118
+ grid-template-columns: 1fr; /* Stack personas vertically in sidebar */
119
+ gap: 16px;
120
+ font-size: 13px;
121
+ }
122
+
123
+ .persona {
124
+ padding: 12px;
125
+ border: 1px solid #e0e0e0;
126
+ border-radius: 2px;
127
+ background: #fdfdfd;
128
+ }
129
+
130
+ .persona h3 {
131
+ margin-bottom: 6px;
132
+ font-size: 14px;
133
+ font-weight: 500;
134
+ }
135
+
136
+ .traits {
137
+ margin: 6px 0;
138
+ }
139
+
140
+ .trait {
141
+ display: inline-block;
142
+ background: #f0f0f0;
143
+ padding: 1px 6px;
144
+ margin: 0 4px 4px 0;
145
+ border-radius: 2px;
146
+ font-size: 11px;
147
+ }
148
+
149
+ /* --- Chat Area (Right Panel) --- */
150
+ .chat-area {
151
+ padding: 20px 40px;
152
+ overflow-y: auto; /* The magic: only this area scrolls */
153
+ flex-grow: 1; /* Fills the vertical space */
154
+ }
155
+
156
+ .message-group {
157
+ margin-bottom: 16px;
158
+ }
159
+
160
+ .message {
161
+ max-width: 70%;
162
+ margin-bottom: 6px;
163
+ padding: 10px 12px;
164
+ border-radius: 4px;
165
+ font-size: 14px;
166
+ }
167
+
168
+ .message.persona1 {
169
+ background: #e1e1e1;
170
+ margin-left: auto;
171
+ }
172
+
173
+ .message.persona2 {
174
+ background: #f0f0f0;
175
+ margin-right: auto;
176
+ }
177
+
178
+ .sender-name {
179
+ font-weight: 500;
180
+ font-size: 11px;
181
+ margin-bottom: 4px;
182
+ opacity: 0.7;
183
+ text-transform: uppercase;
184
+ }
185
+
186
+ /* --- Message Content and Special Elements --- */
187
+ .message-content {
188
+ word-wrap: break-word;
189
+ }
190
+
191
+ .special-element {
192
+ margin: 6px 0;
193
+ padding: 6px 8px;
194
+ background: rgba(0, 0, 0, 0.03);
195
+ border-left: 2px solid #ccc;
196
+ font-size: 12px;
197
+ font-style: italic;
198
+ }
199
+ .image-element {
200
+ border-left-color: #4caf50;
201
+ }
202
+ .video-element {
203
+ border-left-color: #4caf50;
204
+ }
205
+ .audio-element {
206
+ border-left-color: #ff9800;
207
+ }
208
+ .delay-element {
209
+ border-left-color: #9c27b0;
210
+ text-align: center;
211
+ }
212
+ .gif-element {
213
+ border-left-color: #03a9f4;
214
+ }
215
+ .code {
216
+ background: #f0f0f0;
217
+ padding: 1px 4px;
218
+ border-radius: 2px;
219
+ font-family: monospace;
220
+ font-size: 12px;
221
+ }
222
+
223
+ /* --- Responsive Adjustments --- */
224
+ @media (max-width: 768px) {
225
+ .sidebar {
226
+ width: 300px; /* Slimmer sidebar on smaller screens */
227
+ }
228
+ .message {
229
+ max-width: 85%;
230
+ }
231
+ .chat-area {
232
+ padding: 20px;
233
+ }
234
+ }
235
+ </style>
236
+ </head>
237
+ <body>
238
+ <div class="app-container">
239
+ <div class="sidebar">
240
+ <div class="input-section">
241
+ <h1>JSONL Visualizer</h1>
242
+ <textarea
243
+ id="jsonInput"
244
+ placeholder="Paste your JSONL data here..."
245
+ ></textarea>
246
+ <button id="parseBtn">Parse</button>
247
+ <div id="error" class="error"></div>
248
+ </div>
249
+ <div class="header-info" id="headerInfo">
250
+ <h2>Conversation Details</h2>
251
+ <div class="situation-info" id="situationInfo"></div>
252
+ <div class="personas" id="personasInfo"></div>
253
+ </div>
254
+ </div>
255
+
256
+ <div class="main-content" id="mainContent">
257
+ <div class="chat-area" id="chatArea"></div>
258
+ </div>
259
+ </div>
260
+
261
+ <script>
262
+ document
263
+ .getElementById("parseBtn")
264
+ .addEventListener("click", parseConversation);
265
+
266
+ function parseConversation() {
267
+ const input = document.getElementById("jsonInput").value.trim();
268
+ const errorDiv = document.getElementById("error");
269
+ const headerInfo = document.getElementById("headerInfo");
270
+ const mainContent = document.getElementById("mainContent");
271
+
272
+ // Reset view on each parse attempt
273
+ errorDiv.style.display = "none";
274
+ headerInfo.style.display = "none";
275
+ mainContent.style.display = "none";
276
+
277
+ if (!input) {
278
+ errorDiv.textContent = "Input cannot be empty.";
279
+ errorDiv.style.display = "block";
280
+ return;
281
+ }
282
+
283
+ try {
284
+ const data = JSON.parse(input);
285
+ // Show the components on successful parse
286
+ headerInfo.style.display = "block";
287
+ mainContent.style.display = "flex"; // Use flex as it's a flex container
288
+ renderConversation(data);
289
+ } catch (e) {
290
+ errorDiv.textContent = "Error parsing JSON: " + e.message;
291
+ errorDiv.style.display = "block";
292
+ }
293
+ }
294
+
295
+ function renderConversation(data) {
296
+ renderHeader(data);
297
+ renderChat(data.chat_parts, data.experience);
298
+ }
299
+
300
+ function renderHeader(data) {
301
+ const situationInfo = document.getElementById("situationInfo");
302
+ const personasInfo = document.getElementById("personasInfo");
303
+
304
+ situationInfo.innerHTML = `
305
+ <p><strong>Relationship:</strong> ${data.experience.relationship}</p>
306
+ <p><strong>Context:</strong> ${data.experience.situation}</p>
307
+ <p><strong>Topic:</strong> ${data.experience.topic}</p>
308
+ `;
309
+
310
+ const persona1 = data.experience.persona1;
311
+ const persona2 = data.experience.persona2;
312
+
313
+ personasInfo.innerHTML = `
314
+ <div class="persona">
315
+ <h3>${persona1.name} (${persona1.age})</h3>
316
+ <div class="traits">
317
+ ${persona1.traits.map((trait) => `<span class="trait">${trait}</span>`).join("")}
318
+ </div>
319
+ <p><strong>Background:</strong> ${persona1.background}</p>
320
+ <p><strong>Style:</strong> ${persona1.chatting_style}</p>
321
+ </div>
322
+ <div class="persona">
323
+ <h3>${persona2.name} (${persona2.age})</h3>
324
+ <div class="traits">
325
+ ${persona2.traits.map((trait) => `<span class="trait">${trait}</span>`).join("")}
326
+ </div>
327
+ <p><strong>Background:</strong> ${persona2.background}</p>
328
+ <p><strong>Style:</strong> ${persona2.chatting_style}</p>
329
+ </div>
330
+ `;
331
+ }
332
+
333
+ function renderChat(chatParts, experience) {
334
+ const chatArea = document.getElementById("chatArea");
335
+ chatArea.innerHTML = "";
336
+
337
+ chatParts.forEach((part) => {
338
+ const senderClass =
339
+ part.sender === experience.persona1.id
340
+ ? "persona1"
341
+ : "persona2";
342
+ const senderName =
343
+ part.sender === experience.persona1.id
344
+ ? experience.persona1.name
345
+ : experience.persona2.name;
346
+
347
+ const messageGroup = document.createElement("div");
348
+ messageGroup.className = "message-group";
349
+
350
+ part.messages.forEach((messageContent) => {
351
+ const messageDiv = document.createElement("div");
352
+ messageDiv.className = `message ${senderClass}`;
353
+
354
+ const senderDiv = document.createElement("div");
355
+ senderDiv.className = "sender-name";
356
+ senderDiv.textContent = senderName;
357
+
358
+ const contentDiv = document.createElement("div");
359
+ contentDiv.className = "message-content";
360
+ contentDiv.innerHTML = formatMessage(messageContent);
361
+
362
+ messageDiv.appendChild(senderDiv);
363
+ messageDiv.appendChild(contentDiv);
364
+ messageGroup.appendChild(messageDiv);
365
+ });
366
+ chatArea.appendChild(messageGroup);
367
+ });
368
+ // Scroll to the bottom of the chat on render
369
+ chatArea.scrollTop = chatArea.scrollHeight;
370
+ }
371
+
372
+ function formatMessage(content) {
373
+ content = content.replace(/</g, "&lt;").replace(/>/g, "&gt;"); // Basic sanitization first
374
+ content = content.replace(
375
+ /&lt;image&gt;(.*?)&lt;\/image&gt;/g,
376
+ '<div class="special-element image-element">πŸ“· Image: $1</div>',
377
+ );
378
+ content = content.replace(
379
+ /&lt;video&gt;(.*?)&lt;\/video&gt;/g,
380
+ '<div class="special-element video-element">πŸŽ₯ Video: $1</div>',
381
+ );
382
+ content = content.replace(
383
+ /&lt;audio&gt;(.*?)&lt;\/audio&gt;/g,
384
+ '<div class="special-element audio-element">πŸ”Š Audio: $1</div>',
385
+ );
386
+ content = content.replace(
387
+ /&lt;gif&gt;(.*?)&lt;\/gif&gt;/g,
388
+ '<div class="special-element gif-element">🎞️ GIF: $1</div>',
389
+ );
390
+ content = content.replace(
391
+ /&lt;delay\s+(?:hours="(\d+)"\s*)?(?:minutes="(\d+)"\s*)?(?:\/)?&gt;/g,
392
+ function (match, hours, minutes) {
393
+ let delay = "";
394
+ if (hours) delay += hours + "h ";
395
+ if (minutes) delay += minutes + "m";
396
+ return `<div class="special-element delay-element">⏱️ Delay: ${delay || "unknown"}</div>`;
397
+ },
398
+ );
399
+ content = content.replace(
400
+ /&lt;end\/&gt;/g,
401
+ '<div class="special-element">πŸ”š End</div>',
402
+ );
403
+ content = content.replace(
404
+ /&lt;code&gt;(.*?)&lt;\/code&gt;/g,
405
+ '<span class="code">$1</span>',
406
+ );
407
+ content = content.replace(/\n/g, "<br>");
408
+ return content;
409
+ }
410
+
411
+ document
412
+ .getElementById("jsonInput")
413
+ .addEventListener("keydown", function (e) {
414
+ if (e.ctrlKey && e.key === "Enter") {
415
+ parseConversation();
416
+ }
417
+ });
418
+ </script>
419
+ </body>
420
  </html>