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

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +149 -26
index.html CHANGED
@@ -3,7 +3,7 @@
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
  * {
@@ -55,22 +55,47 @@
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;
@@ -80,12 +105,19 @@
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;
@@ -238,12 +270,31 @@
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">
@@ -259,29 +310,110 @@
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
@@ -331,7 +463,6 @@
331
  }
332
 
333
  function renderChat(chatParts, experience) {
334
- const chatArea = document.getElementById("chatArea");
335
  chatArea.innerHTML = "";
336
 
337
  chatParts.forEach((part) => {
@@ -407,14 +538,6 @@
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>
 
3
  <head>
4
  <meta charset="UTF-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>SOC Visualizer</title>
7
  <style>
8
  /* --- Reset and Global Styles --- */
9
  * {
 
55
  }
56
 
57
  .input-section h1 {
58
+ margin-bottom: 16px;
59
  font-size: 20px;
60
  font-weight: 500;
61
  }
62
 
63
+ .input-section h2 {
64
+ font-size: 14px;
65
+ font-weight: 500;
66
+ margin-top: 16px;
67
+ margin-bottom: 8px;
68
+ color: #555;
69
+ }
70
+
71
+ .input-group {
72
+ margin-bottom: 12px;
73
+ }
74
+
75
+ .input-group label {
76
+ display: block;
77
+ font-size: 13px;
78
+ margin-bottom: 4px;
79
+ }
80
+
81
+ .input-group select,
82
  #jsonInput {
83
  width: 100%;
84
+ padding: 8px;
 
85
  border: 1px solid #ccc;
86
  border-radius: 2px;
87
+ font-size: 13px;
88
+ background-color: #fff;
89
+ }
90
+
91
+ #jsonInput {
92
+ height: 120px;
93
  font-family: monospace;
94
  font-size: 12px;
95
  resize: vertical;
96
  }
97
 
98
+ #loadBtn,
99
  #parseBtn {
100
  margin-top: 8px;
101
  padding: 8px 16px;
 
105
  border-radius: 2px;
106
  cursor: pointer;
107
  font-size: 13px;
108
+ width: 100%;
109
  }
110
 
111
+ #loadBtn:hover,
112
  #parseBtn:hover {
113
  background: #555;
114
  }
115
 
116
+ #loadBtn:disabled {
117
+ background: #ccc;
118
+ cursor: not-allowed;
119
+ }
120
+
121
  .error {
122
  color: #d73a49;
123
  margin-top: 8px;
 
270
  <div class="app-container">
271
  <div class="sidebar">
272
  <div class="input-section">
273
+ <h1>SOC Visualizer</h1>
274
+
275
+ <div class="input-group">
276
+ <label for="fileSelector">1. Select a file</label>
277
+ <select id="fileSelector">
278
+ <option value="">-- Choose a file --</option>
279
+ </select>
280
+ </div>
281
+
282
+ <div class="input-group">
283
+ <label for="lineSelector">2. Select a conversation</label>
284
+ <select id="lineSelector" disabled></select>
285
+ </div>
286
+
287
+ <button id="loadBtn" disabled>Load Conversation</button>
288
+
289
+ <hr style="margin: 24px 0" />
290
+
291
+ <h2>Or Paste Manually</h2>
292
  <textarea
293
  id="jsonInput"
294
+ placeholder="Paste a single JSON conversation object here..."
295
  ></textarea>
296
+ <button id="parseBtn">Parse Manual Input</button>
297
+
298
  <div id="error" class="error"></div>
299
  </div>
300
  <div class="header-info" id="headerInfo">
 
310
  </div>
311
 
312
  <script>
313
+ // --- VIRTUAL FILE SYSTEM ---
314
+ // In a real application, you would fetch these files.
315
+ // For this tool, simply add your JSONL file content here.
316
+ // Each key is a filename, and the value is the file's content as a string.
317
+ // Each line in the string must be a complete, valid JSON object.
318
+ const virtualFiles = {
319
+ "soc_sample_1.jsonl": `{ "experience": { "persona1": { "id": "p1", "name": "Alex", "age": 28, "traits": ["tech-savvy", "impatient", "witty"], "background": "Software developer who loves sci-fi movies.", "chatting_style": "Uses short sentences and a lot of tech jargon." }, "persona2": { "id": "p2", "name": "Ben", "age": 30, "traits": ["patient", "thoughtful", "curious"], "background": "Librarian who enjoys classic literature.", "chatting_style": "Writes in full paragraphs and asks many questions." }, "relationship": "Friends", "situation": "Discussing a new movie they both saw.", "topic": "Movie review" }, "chat_parts": [ { "sender": "p1", "messages": ["Did you see 'Galaxy Runners'? The CGI was insane."] }, { "sender": "p2", "messages": ["I did! I found the plot to be a bit derivative of older films, though. What did you think of the story itself?"] }, { "sender": "p1", "messages": ["Story? lol who cares. The FTL jumps looked amazing.", "And that scene with the alien armada... <gif>mind_blown.gif</gif>"] }, { "sender": "p2", "messages": ["Haha, fair enough. The visual spectacle was certainly its strong suit. I just wish they had spent more time developing the main character's motivations."] } ] }
320
+ { "experience": { "persona1": { "id": "p1", "name": "Chloe", "age": 22, "traits": ["energetic", "loves food", "uses emojis"], "background": "Culinary student exploring new cafes.", "chatting_style": "Very casual, lots of emojis and slang." }, "persona2": { "id": "p2", "name": "David", "age": 24, "traits": ["calm", "methodical", "minimalist"], "background": "Architecture student who prefers quiet places.", "chatting_style": "Concise and to the point." }, "relationship": "Siblings", "situation": "Making plans for the weekend.", "topic": "Weekend plans" }, "chat_parts": [ { "sender": "p1", "messages": ["heyyyy!! what r u up to this weekend? 🀩"] }, { "sender": "p2", "messages": ["Not much. Probably finishing up my model for studio."] }, { "sender": "p1", "messages": ["omg nooo you have to come with me to this new brunch place downtown! πŸ₯žπŸ§‡πŸ₯‘", "the pics look amazing!! <image>brunch_spread.jpg</image>"] }, { "sender": "p2", "messages": ["Hah, looks intense. Maybe. What time?"] }, { "sender": "p1", "messages": ["11am! be there or be square! πŸ˜‰"] } ] }`,
321
+ "soc_sample_2.jsonl": `{ "experience": { "persona1": { "id": "p1", "name": "Sarah", "age": 45, "traits": ["organized", "caring", "formal"], "background": "Project manager and mother of two.", "chatting_style": "Proper grammar and punctuation, plans everything." }, "persona2": { "id": "p2", "name": "Tom", "age": 46, "traits": ["forgetful", "easy-going", "humorous"], "background": "Graphic designer who works from home.", "chatting_style": "Casual, uses ellipses, often cracks jokes." }, "relationship": "Married Couple", "situation": "Coordinating grocery shopping.", "topic": "Groceries" }, "chat_parts": [ { "sender": "p1", "messages": ["Hi honey, I'm heading to the store after work. I've shared the updated grocery list with you. Please take a look."] }, { "sender": "p2", "messages": ["Hey! ok will check... pretty sure we still have milk tho?"] }, { "sender": "p1", "messages": ["The kids finished it this morning. Please double-check the list for quantities. I don't want to forget the baking soda for Maya's science project again."] }, { "sender": "p2", "messages": ["oops right! science fair volcano... classic.", "got it. list looks good. grab me some of those fancy chips? πŸ™", "the sea salt and vinegar ones"] } ] }`,
322
+ };
323
+ // --- END VIRTUAL FILE SYSTEM ---
324
+
325
+ // --- DOM Elements ---
326
+ const fileSelector = document.getElementById("fileSelector");
327
+ const lineSelector = document.getElementById("lineSelector");
328
+ const loadBtn = document.getElementById("loadBtn");
329
+ const parseBtn = document.getElementById("parseBtn");
330
+ const jsonInput = document.getElementById("jsonInput");
331
+ const errorDiv = document.getElementById("error");
332
+ const headerInfo = document.getElementById("headerInfo");
333
+ const mainContent = document.getElementById("mainContent");
334
+ const chatArea = document.getElementById("chatArea");
335
+
336
+ // --- Event Listeners ---
337
+ document.addEventListener("DOMContentLoaded", initialize);
338
+ fileSelector.addEventListener("change", handleFileSelection);
339
+ loadBtn.addEventListener("click", loadSelectedConversation);
340
+ parseBtn.addEventListener("click", parseManualInput);
341
+ jsonInput.addEventListener("keydown", function (e) {
342
+ if ((e.ctrlKey || e.metaKey) && e.key === "Enter") {
343
+ parseManualInput();
344
+ }
345
+ });
346
+
347
+ // --- Functions ---
348
+ function initialize() {
349
+ // Populate the file selector on page load
350
+ Object.keys(virtualFiles).forEach((filename) => {
351
+ const option = document.createElement("option");
352
+ option.value = filename;
353
+ option.textContent = filename;
354
+ fileSelector.appendChild(option);
355
+ });
356
+ }
357
 
358
+ function handleFileSelection() {
359
+ const selectedFile = fileSelector.value;
360
+ lineSelector.innerHTML = ""; // Clear previous options
361
+ if (selectedFile) {
362
+ const content = virtualFiles[selectedFile];
363
+ const lines = content.split("\n").filter((line) => line.trim() !== "");
364
+
365
+ lines.forEach((line, index) => {
366
+ const option = document.createElement("option");
367
+ option.value = index;
368
+ // Try to parse to get a topic for a better label
369
+ try {
370
+ const data = JSON.parse(line);
371
+ option.textContent = `Conversation ${index + 1}: ${data.experience.topic}`;
372
+ } catch (e) {
373
+ option.textContent = `Conversation ${index + 1}`;
374
+ }
375
+ lineSelector.appendChild(option);
376
+ });
377
+
378
+ lineSelector.disabled = false;
379
+ loadBtn.disabled = false;
380
+ } else {
381
+ lineSelector.disabled = true;
382
+ loadBtn.disabled = true;
383
+ }
384
+ }
385
 
386
+ function loadSelectedConversation() {
387
+ const fileName = fileSelector.value;
388
+ const lineIndex = lineSelector.value;
389
+
390
+ if (fileName && lineIndex !== null) {
391
+ const content = virtualFiles[fileName];
392
+ const lines = content.split("\n");
393
+ const jsonString = lines[lineIndex];
394
+ processAndRender(jsonString);
395
+ }
396
+ }
397
+
398
+ function parseManualInput() {
399
+ const jsonString = jsonInput.value.trim();
400
+ processAndRender(jsonString);
401
+ }
402
+
403
+ function processAndRender(jsonString) {
404
  // Reset view on each parse attempt
405
  errorDiv.style.display = "none";
406
  headerInfo.style.display = "none";
407
  mainContent.style.display = "none";
408
 
409
+ if (!jsonString) {
410
  errorDiv.textContent = "Input cannot be empty.";
411
  errorDiv.style.display = "block";
412
  return;
413
  }
414
 
415
  try {
416
+ const data = JSON.parse(jsonString);
417
  // Show the components on successful parse
418
  headerInfo.style.display = "block";
419
  mainContent.style.display = "flex"; // Use flex as it's a flex container
 
463
  }
464
 
465
  function renderChat(chatParts, experience) {
 
466
  chatArea.innerHTML = "";
467
 
468
  chatParts.forEach((part) => {
 
538
  content = content.replace(/\n/g, "<br>");
539
  return content;
540
  }
 
 
 
 
 
 
 
 
541
  </script>
542
  </body>
543
  </html>