CultriX commited on
Commit
8f18fd1
·
verified ·
1 Parent(s): cc3dafd

Add 3 files

Browse files
Files changed (3) hide show
  1. README.md +7 -5
  2. index.html +1427 -19
  3. prompts.txt +1 -0
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Deepsite
3
- emoji: 👁
4
- colorFrom: red
5
- colorTo: green
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: deepsite
3
+ emoji: 🐳
4
+ colorFrom: pink
5
+ colorTo: gray
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,1427 @@
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>Dataset Converter | Finetuning Assistant</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ .dropzone {
11
+ border: 2px dashed #cbd5e0;
12
+ transition: all 0.3s ease;
13
+ }
14
+ .dropzone.active {
15
+ border-color: #4f46e5;
16
+ background-color: #f0f4ff;
17
+ }
18
+ .dropzone.error {
19
+ border-color: #ef4444;
20
+ background-color: #fef2f2;
21
+ }
22
+ .dropzone.success {
23
+ border-color: #10b981;
24
+ background-color: #ecfdf5;
25
+ }
26
+ .preset-card {
27
+ transition: all 0.2s ease;
28
+ }
29
+ .preset-card:hover {
30
+ transform: translateY(-2px);
31
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
32
+ }
33
+ .preset-card.selected {
34
+ border-color: #4f46e5;
35
+ background-color: #f0f4ff;
36
+ }
37
+ .header-input:focus {
38
+ outline: none;
39
+ box-shadow: 0 0 0 2px rgba(79, 70, 229, 0.5);
40
+ }
41
+ .smooth-transition {
42
+ transition: all 0.3s ease;
43
+ }
44
+ .preview-container {
45
+ max-height: 300px;
46
+ overflow-y: auto;
47
+ }
48
+ .preview-container::-webkit-scrollbar {
49
+ width: 6px;
50
+ }
51
+ .preview-container::-webkit-scrollbar-track {
52
+ background: #f1f1f1;
53
+ }
54
+ .preview-container::-webkit-scrollbar-thumb {
55
+ background: #888;
56
+ border-radius: 3px;
57
+ }
58
+ .preview-container::-webkit-scrollbar-thumb:hover {
59
+ background: #555;
60
+ }
61
+ .progress-bar {
62
+ height: 4px;
63
+ background-color: #e5e7eb;
64
+ border-radius: 2px;
65
+ overflow: hidden;
66
+ }
67
+ .progress-bar-fill {
68
+ height: 100%;
69
+ background-color: #4f46e5;
70
+ transition: width 0.3s ease;
71
+ }
72
+ .file-info {
73
+ display: none;
74
+ }
75
+ .spinner {
76
+ animation: spin 1s linear infinite;
77
+ }
78
+ @keyframes spin {
79
+ 0% { transform: rotate(0deg); }
80
+ 100% { transform: rotate(360deg); }
81
+ }
82
+ .transform-section {
83
+ display: none;
84
+ }
85
+ .transform-section.active {
86
+ display: block;
87
+ }
88
+ .tab-button {
89
+ transition: all 0.2s ease;
90
+ }
91
+ .tab-button.active {
92
+ border-bottom: 2px solid #4f46e5;
93
+ color: #4f46e5;
94
+ }
95
+ </style>
96
+ </head>
97
+ <body class="bg-gray-50 min-h-screen">
98
+ <div class="container mx-auto px-4 py-8 max-w-6xl">
99
+ <!-- Header -->
100
+ <header class="mb-10 text-center">
101
+ <h1 class="text-4xl font-bold text-indigo-700 mb-2">Dataset Converter</h1>
102
+ <p class="text-gray-600 text-lg">Quickly transform datasets for AI fine-tuning with one-click presets</p>
103
+ </header>
104
+
105
+ <!-- Main Content -->
106
+ <div class="bg-white rounded-xl shadow-lg overflow-hidden">
107
+ <!-- Step Navigation -->
108
+ <div class="flex border-b border-gray-200">
109
+ <div class="w-1/3 py-4 px-6 text-center border-b-2 border-indigo-500 font-medium text-indigo-600">
110
+ <i class="fas fa-upload mr-2"></i> Upload Data
111
+ </div>
112
+ <div class="w-1/3 py-4 px-6 text-center border-b-2 border-gray-200 font-medium text-gray-500">
113
+ <i class="fas fa-magic mr-2"></i> Transform
114
+ </div>
115
+ <div class="w-1/3 py-4 px-6 text-center border-b-2 border-gray-200 font-medium text-gray-500">
116
+ <i class="fas fa-download mr-2"></i> Download
117
+ </div>
118
+ </div>
119
+
120
+ <!-- Step 1: Upload Data -->
121
+ <div id="step1" class="p-8">
122
+ <div class="mb-6">
123
+ <h2 class="text-2xl font-semibold text-gray-800 mb-3">Upload Your Dataset</h2>
124
+ <p class="text-gray-600">Supported formats: CSV, JSON, Excel, TSV (Max 10MB)</p>
125
+ </div>
126
+
127
+ <div id="dropzone" class="dropzone rounded-lg p-12 text-center cursor-pointer mb-4">
128
+ <div id="upload-icon" class="mx-auto w-16 h-16 bg-indigo-100 rounded-full flex items-center justify-center mb-4">
129
+ <i class="fas fa-cloud-upload-alt text-indigo-500 text-2xl"></i>
130
+ </div>
131
+ <h3 id="dropzone-title" class="text-lg font-medium text-gray-700 mb-1">Drag & drop your file here</h3>
132
+ <p id="dropzone-subtitle" class="text-gray-500 mb-4">or</p>
133
+ <label for="file-upload" class="inline-flex items-center px-4 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 cursor-pointer">
134
+ <i class="fas fa-folder-open mr-2"></i> Browse Files
135
+ <input id="file-upload" type="file" class="hidden" accept=".csv,.json,.xlsx,.xls,.tsv">
136
+ </label>
137
+ <div id="progress-container" class="mt-4 hidden">
138
+ <div class="progress-bar">
139
+ <div id="progress-bar-fill" class="progress-bar-fill" style="width: 0%"></div>
140
+ </div>
141
+ <p id="progress-text" class="text-sm text-gray-500 mt-1">Uploading...</p>
142
+ </div>
143
+ <div id="file-info" class="file-info mt-4 p-3 bg-gray-50 rounded-lg">
144
+ <div class="flex items-center justify-between">
145
+ <div class="flex items-center truncate">
146
+ <i id="file-icon" class="fas fa-file-alt text-indigo-500 mr-2"></i>
147
+ <span id="file-name" class="text-sm font-medium text-gray-700 truncate"></span>
148
+ </div>
149
+ <button id="remove-file" class="text-red-500 hover:text-red-700">
150
+ <i class="fas fa-times"></i>
151
+ </button>
152
+ </div>
153
+ <div id="file-meta" class="text-xs text-gray-500 mt-1"></div>
154
+ </div>
155
+ <div id="error-message" class="hidden mt-4 p-3 bg-red-50 text-red-600 rounded-lg text-sm"></div>
156
+ </div>
157
+
158
+ <div class="flex justify-between items-center">
159
+ <div class="text-sm text-gray-500">
160
+ <i class="fas fa-info-circle mr-1"></i> Your data remains private and is processed locally.
161
+ </div>
162
+ <button id="next-step-1" class="px-6 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50 disabled:cursor-not-allowed" disabled>
163
+ Next <i class="fas fa-arrow-right ml-2"></i>
164
+ </button>
165
+ </div>
166
+ </div>
167
+
168
+ <!-- Step 2: Transform Data -->
169
+ <div id="step2" class="p-8 hidden">
170
+ <div class="mb-6">
171
+ <h2 class="text-2xl font-semibold text-gray-800 mb-3">Transform Your Dataset</h2>
172
+ <p class="text-gray-600">Choose a preset or customize the transformation</p>
173
+ </div>
174
+
175
+ <!-- Transformation Tabs -->
176
+ <div class="flex border-b border-gray-200 mb-6">
177
+ <button class="tab-button active px-4 py-2 font-medium text-sm focus:outline-none" data-tab="presets">
178
+ <i class="fas fa-bolt mr-2"></i> Quick Presets
179
+ </button>
180
+ <button class="tab-button px-4 py-2 font-medium text-sm text-gray-500 focus:outline-none" data-tab="custom">
181
+ <i class="fas fa-sliders-h mr-2"></i> Custom Settings
182
+ </button>
183
+ </div>
184
+
185
+ <!-- Presets Section -->
186
+ <div id="presets-section" class="transform-section active">
187
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 mb-6">
188
+ <!-- Preset Cards -->
189
+ <div class="preset-card p-4 border rounded-lg cursor-pointer bg-white" data-preset="chat">
190
+ <div class="flex items-center mb-2">
191
+ <div class="w-10 h-10 rounded-full bg-indigo-100 flex items-center justify-center mr-3">
192
+ <i class="fas fa-comments text-indigo-500"></i>
193
+ </div>
194
+ <h3 class="font-medium">Chat Format</h3>
195
+ </div>
196
+ <p class="text-sm text-gray-600">Converts to {"messages": [{"role": "user", "content": "..."}]}</p>
197
+ <div class="mt-3 text-xs text-indigo-600">
198
+ <i class="fas fa-check-circle mr-1"></i> Best for conversational AI
199
+ </div>
200
+ </div>
201
+
202
+ <div class="preset-card p-4 border rounded-lg cursor-pointer bg-white" data-preset="instruction">
203
+ <div class="flex items-center mb-2">
204
+ <div class="w-10 h-10 rounded-full bg-green-100 flex items-center justify-center mr-3">
205
+ <i class="fas fa-graduation-cap text-green-500"></i>
206
+ </div>
207
+ <h3 class="font-medium">Instruction Format</h3>
208
+ </div>
209
+ <p class="text-sm text-gray-600">Converts to {"instruction": "...", "response": "..."}</p>
210
+ <div class="mt-3 text-xs text-green-600">
211
+ <i class="fas fa-check-circle mr-1"></i> Best for instruction-following models
212
+ </div>
213
+ </div>
214
+
215
+ <div class="preset-card p-4 border rounded-lg cursor-pointer bg-white" data-preset="qa">
216
+ <div class="flex items-center mb-2">
217
+ <div class="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center mr-3">
218
+ <i class="fas fa-question-circle text-blue-500"></i>
219
+ </div>
220
+ <h3 class="font-medium">Q&A Format</h3>
221
+ </div>
222
+ <p class="text-sm text-gray-600">Converts to {"question": "...", "answer": "..."}</p>
223
+ <div class="mt-3 text-xs text-blue-600">
224
+ <i class="fas fa-check-circle mr-1"></i> Best for question answering
225
+ </div>
226
+ </div>
227
+
228
+ <div class="preset-card p-4 border rounded-lg cursor-pointer bg-white" data-preset="completion">
229
+ <div class="flex items-center mb-2">
230
+ <div class="w-10 h-10 rounded-full bg-purple-100 flex items-center justify-center mr-3">
231
+ <i class="fas fa-align-left text-purple-500"></i>
232
+ </div>
233
+ <h3 class="font-medium">Completion Format</h3>
234
+ </div>
235
+ <p class="text-sm text-gray-600">Converts to {"prompt": "...", "completion": "..."}</p>
236
+ <div class="mt-3 text-xs text-purple-600">
237
+ <i class="fas fa-check-circle mr-1"></i> Best for text completion
238
+ </div>
239
+ </div>
240
+
241
+ <div class="preset-card p-4 border rounded-lg cursor-pointer bg-white" data-preset="rename">
242
+ <div class="flex items-center mb-2">
243
+ <div class="w-10 h-10 rounded-full bg-yellow-100 flex items-center justify-center mr-3">
244
+ <i class="fas fa-tags text-yellow-500"></i>
245
+ </div>
246
+ <h3 class="font-medium">Rename Columns</h3>
247
+ </div>
248
+ <p class="text-sm text-gray-600">Lets you rename columns without changing structure</p>
249
+ <div class="mt-3 text-xs text-yellow-600">
250
+ <i class="fas fa-check-circle mr-1"></i> Basic transformation
251
+ </div>
252
+ </div>
253
+
254
+ <div class="preset-card p-4 border rounded-lg cursor-pointer bg-white" data-preset="custom">
255
+ <div class="flex items-center mb-2">
256
+ <div class="w-10 h-10 rounded-full bg-pink-100 flex items-center justify-center mr-3">
257
+ <i class="fas fa-code text-pink-500"></i>
258
+ </div>
259
+ <h3 class="font-medium">Custom Template</h3>
260
+ </div>
261
+ <p class="text-sm text-gray-600">Define your own structure with placeholders</p>
262
+ <div class="mt-3 text-xs text-pink-600">
263
+ <i class="fas fa-check-circle mr-1"></i> Advanced users
264
+ </div>
265
+ </div>
266
+ </div>
267
+
268
+ <!-- Preset Configuration -->
269
+ <div id="preset-config" class="hidden mb-6">
270
+ <h3 class="text-lg font-medium text-gray-800 mb-3" id="preset-title">Configure Preset</h3>
271
+
272
+ <div id="chat-config" class="preset-config-section hidden">
273
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
274
+ <div>
275
+ <label class="block text-sm font-medium text-gray-700 mb-1">User Message Column</label>
276
+ <select id="chat-user-col" class="w-full px-3 py-2 border rounded-md focus:ring-indigo-500 focus:border-indigo-500">
277
+ <!-- Dynamically populated -->
278
+ </select>
279
+ </div>
280
+ <div>
281
+ <label class="block text-sm font-medium text-gray-700 mb-1">Assistant Message Column</label>
282
+ <select id="chat-assistant-col" class="w-full px-3 py-2 border rounded-md focus:ring-indigo-500 focus:border-indigo-500">
283
+ <!-- Dynamically populated -->
284
+ </select>
285
+ </div>
286
+ </div>
287
+ <div class="mb-4">
288
+ <label class="block text-sm font-medium text-gray-700 mb-1">System Message (optional)</label>
289
+ <input type="text" id="chat-system-msg" class="w-full px-3 py-2 border rounded-md focus:ring-indigo-500 focus:border-indigo-500" placeholder="You are a helpful assistant...">
290
+ </div>
291
+ </div>
292
+
293
+ <div id="instruction-config" class="preset-config-section hidden">
294
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
295
+ <div>
296
+ <label class="block text-sm font-medium text-gray-700 mb-1">Instruction Column</label>
297
+ <select id="instruction-col" class="w-full px-3 py-2 border rounded-md focus:ring-indigo-500 focus:border-indigo-500">
298
+ <!-- Dynamically populated -->
299
+ </select>
300
+ </div>
301
+ <div>
302
+ <label class="block text-sm font-medium text-gray-700 mb-1">Response Column</label>
303
+ <select id="response-col" class="w-full px-3 py-2 border rounded-md focus:ring-indigo-500 focus:border-indigo-500">
304
+ <!-- Dynamically populated -->
305
+ </select>
306
+ </div>
307
+ </div>
308
+ </div>
309
+
310
+ <div id="qa-config" class="preset-config-section hidden">
311
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
312
+ <div>
313
+ <label class="block text-sm font-medium text-gray-700 mb-1">Question Column</label>
314
+ <select id="question-col" class="w-full px-3 py-2 border rounded-md focus:ring-indigo-500 focus:border-indigo-500">
315
+ <!-- Dynamically populated -->
316
+ </select>
317
+ </div>
318
+ <div>
319
+ <label class="block text-sm font-medium text-gray-700 mb-1">Answer Column</label>
320
+ <select id="answer-col" class="w-full px-3 py-2 border rounded-md focus:ring-indigo-500 focus:border-indigo-500">
321
+ <!-- Dynamically populated -->
322
+ </select>
323
+ </div>
324
+ </div>
325
+ </div>
326
+
327
+ <div id="completion-config" class="preset-config-section hidden">
328
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
329
+ <div>
330
+ <label class="block text-sm font-medium text-gray-700 mb-1">Prompt Column</label>
331
+ <select id="prompt-col" class="w-full px-3 py-2 border rounded-md focus:ring-indigo-500 focus:border-indigo-500">
332
+ <!-- Dynamically populated -->
333
+ </select>
334
+ </div>
335
+ <div>
336
+ <label class="block text-sm font-medium text-gray-700 mb-1">Completion Column</label>
337
+ <select id="completion-col" class="w-full px-3 py-2 border rounded-md focus:ring-indigo-500 focus:border-indigo-500">
338
+ <!-- Dynamically populated -->
339
+ </select>
340
+ </div>
341
+ </div>
342
+ </div>
343
+
344
+ <div id="rename-config" class="preset-config-section hidden">
345
+ <label class="block text-sm font-medium text-gray-700 mb-2">Column Renaming</label>
346
+ <div class="bg-gray-50 p-4 rounded-lg">
347
+ <div class="grid grid-cols-2 gap-4 mb-4">
348
+ <div class="text-sm font-medium text-gray-500">Original Name</div>
349
+ <div class="text-sm font-medium text-gray-500">New Name</div>
350
+ </div>
351
+ <div id="rename-mapping-container">
352
+ <!-- Dynamic rename fields will be inserted here -->
353
+ </div>
354
+ </div>
355
+ </div>
356
+
357
+ <div id="custom-config" class="preset-config-section hidden">
358
+ <label class="block text-sm font-medium text-gray-700 mb-2">Custom Template</label>
359
+ <textarea id="custom-template" class="w-full h-32 px-3 py-2 text-gray-700 border rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500" placeholder="Example: { 'prompt': '{{input}}', 'completion': '{{output}}' }"></textarea>
360
+ <p class="text-xs text-gray-500 mt-1">Use {{column_name}} to reference columns from your data</p>
361
+ </div>
362
+ </div>
363
+ </div>
364
+
365
+ <!-- Custom Settings Section -->
366
+ <div id="custom-section" class="transform-section">
367
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
368
+ <!-- Format Selection -->
369
+ <div class="col-span-1">
370
+ <label class="block text-sm font-medium text-gray-700 mb-2">Output Format</label>
371
+ <div class="space-y-2">
372
+ <div class="p-4 border rounded-lg bg-white">
373
+ <div class="flex items-center">
374
+ <input type="radio" name="format" id="format-json" value="json" class="h-4 w-4 text-indigo-600 focus:ring-indigo-500" checked>
375
+ <label for="format-json" class="ml-3 block text-sm font-medium text-gray-700">JSON</label>
376
+ </div>
377
+ <p class="mt-1 ml-7 text-xs text-gray-500">Structured data with key-value pairs</p>
378
+ </div>
379
+ <div class="p-4 border rounded-lg bg-white">
380
+ <div class="flex items-center">
381
+ <input type="radio" name="format" id="format-csv" value="csv" class="h-4 w-4 text-indigo-600 focus:ring-indigo-500">
382
+ <label for="format-csv" class="ml-3 block text-sm font-medium text-gray-700">CSV</label>
383
+ </div>
384
+ <p class="mt-1 ml-7 text-xs text-gray-500">Comma-separated values</p>
385
+ </div>
386
+ </div>
387
+ </div>
388
+
389
+ <!-- Header Mapping -->
390
+ <div class="col-span-2">
391
+ <label class="block text-sm font-medium text-gray-700 mb-2">Header Mapping</label>
392
+ <div class="bg-gray-50 p-4 rounded-lg">
393
+ <div class="grid grid-cols-2 gap-4 mb-4">
394
+ <div class="text-sm font-medium text-gray-500">Original Header</div>
395
+ <div class="text-sm font-medium text-gray-500">New Header Name</div>
396
+ </div>
397
+ <div id="header-mapping-container">
398
+ <!-- Dynamic header mapping fields will be inserted here -->
399
+ <div class="text-center py-8 text-gray-400">
400
+ <i class="fas fa-table fa-2x mb-2"></i>
401
+ <p>Select a preset or upload a file to see available headers</p>
402
+ </div>
403
+ </div>
404
+ </div>
405
+ </div>
406
+ </div>
407
+ </div>
408
+
409
+ <!-- Preview Section -->
410
+ <div class="mb-6">
411
+ <div class="flex justify-between items-center mb-2">
412
+ <label class="block text-sm font-medium text-gray-700">Preview</label>
413
+ <button id="refresh-preview" class="text-sm text-indigo-600 hover:text-indigo-800 flex items-center">
414
+ <i class="fas fa-sync-alt mr-1"></i> Refresh
415
+ </button>
416
+ </div>
417
+ <div id="preview-content" class="preview-container bg-gray-50 p-4 rounded-lg border border-gray-200 text-sm font-mono">
418
+ <div class="text-center py-8 text-gray-400">
419
+ <i class="fas fa-eye fa-2x mb-2"></i>
420
+ <p>Select a preset or configure settings to see a preview</p>
421
+ </div>
422
+ </div>
423
+ </div>
424
+
425
+ <div class="flex justify-between items-center">
426
+ <button id="prev-step-2" class="px-6 py-2 bg-gray-200 text-gray-700 rounded-md hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500">
427
+ <i class="fas fa-arrow-left mr-2"></i> Back
428
+ </button>
429
+ <button id="next-step-2" class="px-6 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50 disabled:cursor-not-allowed">
430
+ Next <i class="fas fa-arrow-right ml-2"></i>
431
+ </button>
432
+ </div>
433
+ </div>
434
+
435
+ <!-- Step 3: Download Result -->
436
+ <div id="step3" class="p-8 hidden">
437
+ <div class="mb-6">
438
+ <h2 class="text-2xl font-semibold text-gray-800 mb-3">Download Converted Data</h2>
439
+ <p class="text-gray-600">Your dataset has been successfully transformed</p>
440
+ </div>
441
+
442
+ <div class="bg-indigo-50 border border-indigo-100 rounded-lg p-6 text-center mb-8">
443
+ <div class="mx-auto w-16 h-16 bg-indigo-100 rounded-full flex items-center justify-center mb-4">
444
+ <i class="fas fa-check-circle text-indigo-500 text-2xl"></i>
445
+ </div>
446
+ <h3 class="text-lg font-medium text-gray-700 mb-2">Conversion Complete!</h3>
447
+ <p class="text-gray-600 mb-4">Your data is ready for fine-tuning</p>
448
+
449
+ <div class="flex justify-center space-x-4">
450
+ <button id="download-btn" class="px-6 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
451
+ <i class="fas fa-download mr-2"></i> Download
452
+ </button>
453
+ <button id="copy-clipboard" class="px-6 py-2 bg-white text-indigo-600 border border-indigo-300 rounded-md hover:bg-indigo-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
454
+ <i class="fas fa-copy mr-2"></i> Copy to Clipboard
455
+ </button>
456
+ </div>
457
+ </div>
458
+
459
+ <div class="mb-6">
460
+ <label class="block text-sm font-medium text-gray-700 mb-2">Converted Data Preview</label>
461
+ <div id="final-preview" class="preview-container bg-gray-50 p-4 rounded-lg border border-gray-200 text-sm font-mono">
462
+ <!-- Final preview will be shown here -->
463
+ </div>
464
+ </div>
465
+
466
+ <div class="flex justify-between items-center">
467
+ <button id="prev-step-3" class="px-6 py-2 bg-gray-200 text-gray-700 rounded-md hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500">
468
+ <i class="fas fa-arrow-left mr-2"></i> Back
469
+ </button>
470
+ <button id="new-conversion" class="px-6 py-2 bg-indigo-600 text-white rounded-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
471
+ <i class="fas fa-redo mr-2"></i> Start New Conversion
472
+ </button>
473
+ </div>
474
+ </div>
475
+ </div>
476
+
477
+ <!-- Footer -->
478
+ <footer class="mt-12 text-center text-gray-500 text-sm">
479
+ <p>Dataset Converter Tool | Built for AI Fine-tuning | <a href="#" class="text-indigo-600 hover:underline">Privacy Policy</a></p>
480
+ </footer>
481
+ </div>
482
+
483
+ <script>
484
+ // Global variables
485
+ let uploadedFile = null;
486
+ let parsedData = null;
487
+ let headers = [];
488
+ let convertedData = null;
489
+ let selectedPreset = null;
490
+
491
+ // DOM elements
492
+ const dropzone = document.getElementById('dropzone');
493
+ const fileUpload = document.getElementById('file-upload');
494
+ const nextStep1Btn = document.getElementById('next-step-1');
495
+ const step1 = document.getElementById('step1');
496
+ const step2 = document.getElementById('step2');
497
+ const step3 = document.getElementById('step3');
498
+ const headerMappingContainer = document.getElementById('header-mapping-container');
499
+ const previewContent = document.getElementById('preview-content');
500
+ const finalPreview = document.getElementById('final-preview');
501
+ const downloadBtn = document.getElementById('download-btn');
502
+ const copyClipboardBtn = document.getElementById('copy-clipboard');
503
+ const uploadIcon = document.getElementById('upload-icon');
504
+ const dropzoneTitle = document.getElementById('dropzone-title');
505
+ const dropzoneSubtitle = document.getElementById('dropzone-subtitle');
506
+ const progressContainer = document.getElementById('progress-container');
507
+ const progressBarFill = document.getElementById('progress-bar-fill');
508
+ const progressText = document.getElementById('progress-text');
509
+ const fileInfo = document.getElementById('file-info');
510
+ const fileName = document.getElementById('file-name');
511
+ const fileMeta = document.getElementById('file-meta');
512
+ const fileIcon = document.getElementById('file-icon');
513
+ const removeFile = document.getElementById('remove-file');
514
+ const errorMessage = document.getElementById('error-message');
515
+ const presetCards = document.querySelectorAll('.preset-card');
516
+ const presetConfig = document.getElementById('preset-config');
517
+ const presetTitle = document.getElementById('preset-title');
518
+ const tabButtons = document.querySelectorAll('.tab-button');
519
+ const presetsSection = document.getElementById('presets-section');
520
+ const customSection = document.getElementById('custom-section');
521
+
522
+ // Event listeners for navigation
523
+ document.getElementById('next-step-1').addEventListener('click', () => {
524
+ step1.classList.add('hidden');
525
+ step2.classList.remove('hidden');
526
+ updateStepNavigation(2);
527
+ });
528
+
529
+ document.getElementById('prev-step-2').addEventListener('click', () => {
530
+ step2.classList.add('hidden');
531
+ step1.classList.remove('hidden');
532
+ updateStepNavigation(1);
533
+ });
534
+
535
+ document.getElementById('next-step-2').addEventListener('click', () => {
536
+ convertData();
537
+ step2.classList.add('hidden');
538
+ step3.classList.remove('hidden');
539
+ updateStepNavigation(3);
540
+ displayFinalPreview();
541
+ });
542
+
543
+ document.getElementById('prev-step-3').addEventListener('click', () => {
544
+ step3.classList.add('hidden');
545
+ step2.classList.remove('hidden');
546
+ updateStepNavigation(2);
547
+ });
548
+
549
+ document.getElementById('new-conversion').addEventListener('click', () => {
550
+ resetConverter();
551
+ step3.classList.add('hidden');
552
+ step1.classList.remove('hidden');
553
+ updateStepNavigation(1);
554
+ });
555
+
556
+ // Tab switching
557
+ tabButtons.forEach(button => {
558
+ button.addEventListener('click', () => {
559
+ const tab = button.dataset.tab;
560
+
561
+ // Update tab buttons
562
+ tabButtons.forEach(btn => {
563
+ btn.classList.remove('active', 'text-indigo-600');
564
+ btn.classList.add('text-gray-500');
565
+ });
566
+ button.classList.add('active', 'text-indigo-600');
567
+ button.classList.remove('text-gray-500');
568
+
569
+ // Show corresponding section
570
+ if (tab === 'presets') {
571
+ presetsSection.classList.add('active');
572
+ customSection.classList.remove('active');
573
+ } else {
574
+ presetsSection.classList.remove('active');
575
+ customSection.classList.add('active');
576
+ }
577
+ });
578
+ });
579
+
580
+ // Preset selection
581
+ presetCards.forEach(card => {
582
+ card.addEventListener('click', () => {
583
+ // Remove selection from all cards
584
+ presetCards.forEach(c => {
585
+ c.classList.remove('selected');
586
+ c.classList.remove('border-indigo-500');
587
+ c.classList.add('border-gray-200');
588
+ });
589
+
590
+ // Select clicked card
591
+ card.classList.add('selected', 'border-indigo-500');
592
+ card.classList.remove('border-gray-200');
593
+
594
+ // Show configuration for selected preset
595
+ selectedPreset = card.dataset.preset;
596
+ presetConfig.classList.remove('hidden');
597
+ presetTitle.textContent = `Configure ${card.querySelector('h3').textContent}`;
598
+
599
+ // Hide all config sections
600
+ document.querySelectorAll('.preset-config-section').forEach(section => {
601
+ section.classList.add('hidden');
602
+ });
603
+
604
+ // Show selected config section
605
+ document.getElementById(`${selectedPreset}-config`).classList.remove('hidden');
606
+
607
+ // Populate dropdowns if needed
608
+ if (uploadedFile) {
609
+ populatePresetDropdowns();
610
+ }
611
+
612
+ // Update preview
613
+ updatePreview();
614
+ });
615
+ });
616
+
617
+ // Refresh preview button
618
+ document.getElementById('refresh-preview').addEventListener('click', updatePreview);
619
+
620
+ // Download button
621
+ downloadBtn.addEventListener('click', downloadConvertedData);
622
+
623
+ // Copy to clipboard
624
+ copyClipboardBtn.addEventListener('click', copyToClipboard);
625
+
626
+ // Remove file button
627
+ removeFile.addEventListener('click', resetFileUpload);
628
+
629
+ // Dropzone events
630
+ ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
631
+ dropzone.addEventListener(eventName, preventDefaults, false);
632
+ });
633
+
634
+ function preventDefaults(e) {
635
+ e.preventDefault();
636
+ e.stopPropagation();
637
+ }
638
+
639
+ ['dragenter', 'dragover'].forEach(eventName => {
640
+ dropzone.addEventListener(eventName, highlight, false);
641
+ });
642
+
643
+ ['dragleave', 'drop'].forEach(eventName => {
644
+ dropzone.addEventListener(eventName, unhighlight, false);
645
+ });
646
+
647
+ function highlight() {
648
+ dropzone.classList.add('active');
649
+ }
650
+
651
+ function unhighlight() {
652
+ dropzone.classList.remove('active');
653
+ }
654
+
655
+ dropzone.addEventListener('drop', handleDrop, false);
656
+ fileUpload.addEventListener('change', handleFileSelect, false);
657
+
658
+ function handleDrop(e) {
659
+ const dt = e.dataTransfer;
660
+ const files = dt.files;
661
+ if (files.length > 1) {
662
+ showError('Please upload only one file at a time');
663
+ return;
664
+ }
665
+ handleFiles(files);
666
+ }
667
+
668
+ function handleFileSelect(e) {
669
+ if (e.target.files.length > 1) {
670
+ showError('Please upload only one file at a time');
671
+ return;
672
+ }
673
+ handleFiles(e.target.files);
674
+ }
675
+
676
+ function handleFiles(files) {
677
+ if (files.length > 0) {
678
+ const file = files[0];
679
+
680
+ // Check file size (max 10MB)
681
+ if (file.size > 10 * 1024 * 1024) {
682
+ showError('File size exceeds 10MB limit');
683
+ return;
684
+ }
685
+
686
+ // Check file type
687
+ const fileType = file.name.split('.').pop().toLowerCase();
688
+ if (!['csv', 'json', 'xlsx', 'xls', 'tsv'].includes(fileType)) {
689
+ showError('Unsupported file format. Please upload CSV, JSON, Excel, or TSV files.');
690
+ return;
691
+ }
692
+
693
+ // Show loading state
694
+ showUploadingState();
695
+
696
+ // Simulate upload progress (in a real app, this would be actual upload progress)
697
+ let progress = 0;
698
+ const progressInterval = setInterval(() => {
699
+ progress += 5;
700
+ if (progress > 95) {
701
+ clearInterval(progressInterval);
702
+ parseFile(file);
703
+ } else {
704
+ updateProgress(progress);
705
+ }
706
+ }, 50);
707
+ }
708
+ }
709
+
710
+ function showUploadingState() {
711
+ // Hide error if any
712
+ hideError();
713
+
714
+ // Show progress bar
715
+ progressContainer.classList.remove('hidden');
716
+ progressBarFill.style.width = '0%';
717
+ progressText.textContent = 'Uploading...';
718
+
719
+ // Change icon to spinner
720
+ uploadIcon.innerHTML = '<i class="fas fa-spinner spinner text-indigo-500 text-2xl"></i>';
721
+ dropzoneTitle.textContent = 'Uploading your file...';
722
+ dropzoneSubtitle.classList.add('hidden');
723
+ }
724
+
725
+ function updateProgress(percent) {
726
+ progressBarFill.style.width = `${percent}%`;
727
+ progressText.textContent = `Uploading... ${percent}%`;
728
+ }
729
+
730
+ function showFileInfo(file) {
731
+ const fileType = file.name.split('.').pop().toLowerCase();
732
+ const fileSize = formatFileSize(file.size);
733
+
734
+ // Set file icon based on type
735
+ let iconClass = 'fa-file-alt';
736
+ if (fileType === 'csv' || fileType === 'tsv') {
737
+ iconClass = 'fa-file-csv';
738
+ } else if (fileType === 'json') {
739
+ iconClass = 'fa-file-code';
740
+ } else if (fileType === 'xlsx' || fileType === 'xls') {
741
+ iconClass = 'fa-file-excel';
742
+ }
743
+ fileIcon.className = `fas ${iconClass} text-indigo-500 mr-2`;
744
+
745
+ // Set file name and metadata
746
+ fileName.textContent = file.name;
747
+ fileMeta.textContent = `${fileSize} • ${fileType.toUpperCase()} file`;
748
+
749
+ // Show file info and hide progress
750
+ fileInfo.style.display = 'block';
751
+ progressContainer.classList.add('hidden');
752
+
753
+ // Update dropzone appearance
754
+ dropzone.classList.add('success');
755
+ dropzone.classList.remove('active', 'error');
756
+
757
+ // Update upload icon and text
758
+ uploadIcon.innerHTML = '<i class="fas fa-check-circle text-green-500 text-2xl"></i>';
759
+ dropzoneTitle.textContent = 'File uploaded successfully';
760
+ dropzoneSubtitle.classList.add('hidden');
761
+ }
762
+
763
+ function formatFileSize(bytes) {
764
+ if (bytes < 1024) return bytes + ' bytes';
765
+ else if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB';
766
+ else return (bytes / 1048576).toFixed(1) + ' MB';
767
+ }
768
+
769
+ function showError(message) {
770
+ errorMessage.textContent = message;
771
+ errorMessage.classList.remove('hidden');
772
+
773
+ // Update dropzone appearance
774
+ dropzone.classList.add('error');
775
+ dropzone.classList.remove('active', 'success');
776
+
777
+ // Reset upload icon and text
778
+ uploadIcon.innerHTML = '<i class="fas fa-cloud-upload-alt text-indigo-500 text-2xl"></i>';
779
+ dropzoneTitle.textContent = 'Drag & drop your file here';
780
+ dropzoneSubtitle.classList.remove('hidden');
781
+
782
+ // Hide progress and file info
783
+ progressContainer.classList.add('hidden');
784
+ fileInfo.style.display = 'none';
785
+ }
786
+
787
+ function hideError() {
788
+ errorMessage.classList.add('hidden');
789
+ dropzone.classList.remove('error');
790
+ }
791
+
792
+ function resetFileUpload() {
793
+ fileUpload.value = '';
794
+ uploadedFile = null;
795
+ parsedData = null;
796
+ headers = [];
797
+ nextStep1Btn.disabled = true;
798
+
799
+ // Reset dropzone appearance
800
+ dropzone.classList.remove('active', 'error', 'success');
801
+
802
+ // Reset UI elements
803
+ uploadIcon.innerHTML = '<i class="fas fa-cloud-upload-alt text-indigo-500 text-2xl"></i>';
804
+ dropzoneTitle.textContent = 'Drag & drop your file here';
805
+ dropzoneSubtitle.classList.remove('hidden');
806
+ progressContainer.classList.add('hidden');
807
+ fileInfo.style.display = 'none';
808
+ hideError();
809
+
810
+ // Reset header mapping
811
+ headerMappingContainer.innerHTML = `
812
+ <div class="text-center py-8 text-gray-400">
813
+ <i class="fas fa-table fa-2x mb-2"></i>
814
+ <p>Upload a file to see available headers</p>
815
+ </div>
816
+ `;
817
+
818
+ // Reset preview
819
+ previewContent.innerHTML = `
820
+ <div class="text-center py-8 text-gray-400">
821
+ <i class="fas fa-eye fa-2x mb-2"></i>
822
+ <p>Configure settings to see a preview</p>
823
+ </div>
824
+ `;
825
+
826
+ // Reset preset selection
827
+ presetCards.forEach(card => {
828
+ card.classList.remove('selected', 'border-indigo-500');
829
+ card.classList.add('border-gray-200');
830
+ });
831
+ presetConfig.classList.add('hidden');
832
+ selectedPreset = null;
833
+ }
834
+
835
+ function parseFile(file) {
836
+ const reader = new FileReader();
837
+ const fileType = file.name.split('.').pop().toLowerCase();
838
+
839
+ reader.onloadstart = function() {
840
+ progressText.textContent = 'Processing file...';
841
+ };
842
+
843
+ reader.onload = function(e) {
844
+ try {
845
+ if (fileType === 'csv' || fileType === 'tsv') {
846
+ parseCSV(e.target.result, fileType === 'tsv' ? '\t' : ',');
847
+ } else if (fileType === 'json') {
848
+ parsedData = JSON.parse(e.target.result);
849
+ extractHeadersFromJSON();
850
+ } else if (fileType === 'xlsx' || fileType === 'xls') {
851
+ // In a real implementation, you would use SheetJS or similar library
852
+ // For this demo, we'll just show an error
853
+ throw new Error('Excel parsing would require a library like SheetJS. In this demo, please use CSV or JSON.');
854
+ } else {
855
+ throw new Error('Unsupported file format');
856
+ }
857
+
858
+ // Update UI
859
+ uploadedFile = file;
860
+ showFileInfo(file);
861
+ nextStep1Btn.disabled = false;
862
+ updateHeaderMapping();
863
+
864
+ // If a preset is already selected, populate its dropdowns
865
+ if (selectedPreset) {
866
+ populatePresetDropdowns();
867
+ }
868
+
869
+ updatePreview();
870
+
871
+ // Complete progress
872
+ progressBarFill.style.width = '100%';
873
+ progressText.textContent = 'Processing complete!';
874
+ setTimeout(() => progressContainer.classList.add('hidden'), 1000);
875
+ } catch (error) {
876
+ console.error('Error parsing file:', error);
877
+ showError(`Error processing file: ${error.message}`);
878
+ progressContainer.classList.add('hidden');
879
+ }
880
+ };
881
+
882
+ reader.onerror = function() {
883
+ showError('Error reading file. Please try again.');
884
+ progressContainer.classList.add('hidden');
885
+ };
886
+
887
+ if (fileType === 'csv' || fileType === 'tsv' || fileType === 'json') {
888
+ reader.readAsText(file);
889
+ } else {
890
+ reader.readAsBinaryString(file);
891
+ }
892
+ }
893
+
894
+ function parseCSV(data, delimiter) {
895
+ const lines = data.split('\n');
896
+ if (lines.length === 0) {
897
+ throw new Error('File is empty');
898
+ }
899
+
900
+ headers = lines[0].split(delimiter).map(h => h.trim());
901
+ if (headers.length === 0) {
902
+ throw new Error('No headers found in the file');
903
+ }
904
+
905
+ parsedData = [];
906
+
907
+ for (let i = 1; i < lines.length; i++) {
908
+ if (lines[i].trim() === '') continue;
909
+
910
+ const values = lines[i].split(delimiter);
911
+ const row = {};
912
+
913
+ for (let j = 0; j < headers.length; j++) {
914
+ if (j < values.length) {
915
+ row[headers[j]] = values[j].trim();
916
+ } else {
917
+ row[headers[j]] = '';
918
+ }
919
+ }
920
+
921
+ parsedData.push(row);
922
+ }
923
+
924
+ if (parsedData.length === 0) {
925
+ throw new Error('No data rows found in the file');
926
+ }
927
+ }
928
+
929
+ function extractHeadersFromJSON() {
930
+ if (Array.isArray(parsedData) && parsedData.length > 0) {
931
+ headers = Object.keys(parsedData[0]);
932
+ } else if (typeof parsedData === 'object') {
933
+ headers = Object.keys(parsedData);
934
+ // Convert to array format for consistency
935
+ parsedData = [parsedData];
936
+ } else {
937
+ throw new Error('Invalid JSON structure. Expected an array of objects or a single object.');
938
+ }
939
+
940
+ if (headers.length === 0) {
941
+ throw new Error('No headers found in the JSON data');
942
+ }
943
+ }
944
+
945
+ function updateHeaderMapping() {
946
+ headerMappingContainer.innerHTML = '';
947
+
948
+ if (headers.length === 0) {
949
+ headerMappingContainer.innerHTML = `
950
+ <div class="text-center py-8 text-gray-400">
951
+ <i class="fas fa-exclamation-circle fa-2x mb-2"></i>
952
+ <p>No headers found in the uploaded file</p>
953
+ </div>
954
+ `;
955
+ return;
956
+ }
957
+
958
+ headers.forEach(header => {
959
+ const div = document.createElement('div');
960
+ div.className = 'grid grid-cols-2 gap-4 mb-3 items-center';
961
+ div.innerHTML = `
962
+ <div class="text-sm text-gray-700 truncate" title="${header}">${header}</div>
963
+ <input type="text" value="${header}" class="header-input w-full px-3 py-2 text-gray-700 border rounded-md focus:border-indigo-500 smooth-transition" data-original="${header}">
964
+ `;
965
+ headerMappingContainer.appendChild(div);
966
+ });
967
+ }
968
+
969
+ function populatePresetDropdowns() {
970
+ if (!uploadedFile || !selectedPreset) return;
971
+
972
+ // Get all select elements in the current preset config
973
+ const selects = document.querySelectorAll(`#${selectedPreset}-config select`);
974
+
975
+ selects.forEach(select => {
976
+ // Clear existing options
977
+ select.innerHTML = '';
978
+
979
+ // Add default option
980
+ const defaultOption = document.createElement('option');
981
+ defaultOption.value = '';
982
+ defaultOption.textContent = 'Select a column...';
983
+ select.appendChild(defaultOption);
984
+
985
+ // Add options for each header
986
+ headers.forEach(header => {
987
+ const option = document.createElement('option');
988
+ option.value = header;
989
+ option.textContent = header;
990
+ select.appendChild(option);
991
+ });
992
+ });
993
+
994
+ // For rename preset, populate the rename fields
995
+ if (selectedPreset === 'rename') {
996
+ const container = document.getElementById('rename-mapping-container');
997
+ container.innerHTML = '';
998
+
999
+ headers.forEach(header => {
1000
+ const div = document.createElement('div');
1001
+ div.className = 'grid grid-cols-2 gap-4 mb-3 items-center';
1002
+ div.innerHTML = `
1003
+ <div class="text-sm text-gray-700 truncate" title="${header}">${header}</div>
1004
+ <input type="text" value="${header}" class="rename-input w-full px-3 py-2 text-gray-700 border rounded-md focus:border-indigo-500 smooth-transition" data-original="${header}">
1005
+ `;
1006
+ container.appendChild(div);
1007
+ });
1008
+ }
1009
+ }
1010
+
1011
+ function updatePreview() {
1012
+ if (!uploadedFile) return;
1013
+
1014
+ // If using presets tab
1015
+ if (presetsSection.classList.contains('active') && selectedPreset) {
1016
+ let previewText = '';
1017
+
1018
+ if (selectedPreset === 'chat') {
1019
+ const userCol = document.getElementById('chat-user-col').value;
1020
+ const assistantCol = document.getElementById('chat-assistant-col').value;
1021
+ const systemMsg = document.getElementById('chat-system-msg').value;
1022
+
1023
+ if (userCol && assistantCol) {
1024
+ const sample = getSampleData(1)[0];
1025
+ const messages = [
1026
+ systemMsg ? {role: "system", content: systemMsg} : null,
1027
+ {role: "user", content: sample[userCol]},
1028
+ {role: "assistant", content: sample[assistantCol]}
1029
+ ].filter(Boolean);
1030
+
1031
+ previewText = JSON.stringify({messages}, null, 2);
1032
+ } else {
1033
+ previewText = 'Select user and assistant message columns to see preview';
1034
+ }
1035
+ }
1036
+ else if (selectedPreset === 'instruction') {
1037
+ const instructionCol = document.getElementById('instruction-col').value;
1038
+ const responseCol = document.getElementById('response-col').value;
1039
+
1040
+ if (instructionCol && responseCol) {
1041
+ const sample = getSampleData(1)[0];
1042
+ previewText = JSON.stringify({
1043
+ instruction: sample[instructionCol],
1044
+ response: sample[responseCol]
1045
+ }, null, 2);
1046
+ } else {
1047
+ previewText = 'Select instruction and response columns to see preview';
1048
+ }
1049
+ }
1050
+ else if (selectedPreset === 'qa') {
1051
+ const questionCol = document.getElementById('question-col').value;
1052
+ const answerCol = document.getElementById('answer-col').value;
1053
+
1054
+ if (questionCol && answerCol) {
1055
+ const sample = getSampleData(1)[0];
1056
+ previewText = JSON.stringify({
1057
+ question: sample[questionCol],
1058
+ answer: sample[answerCol]
1059
+ }, null, 2);
1060
+ } else {
1061
+ previewText = 'Select question and answer columns to see preview';
1062
+ }
1063
+ }
1064
+ else if (selectedPreset === 'completion') {
1065
+ const promptCol = document.getElementById('prompt-col').value;
1066
+ const completionCol = document.getElementById('completion-col').value;
1067
+
1068
+ if (promptCol && completionCol) {
1069
+ const sample = getSampleData(1)[0];
1070
+ previewText = JSON.stringify({
1071
+ prompt: sample[promptCol],
1072
+ completion: sample[completionCol]
1073
+ }, null, 2);
1074
+ } else {
1075
+ previewText = 'Select prompt and completion columns to see preview';
1076
+ }
1077
+ }
1078
+ else if (selectedPreset === 'rename') {
1079
+ const inputs = document.querySelectorAll('.rename-input');
1080
+ const mapping = {};
1081
+
1082
+ inputs.forEach(input => {
1083
+ mapping[input.dataset.original] = input.value || input.dataset.original;
1084
+ });
1085
+
1086
+ const sample = getSampleData(1)[0];
1087
+ const renamedSample = {};
1088
+
1089
+ for (const oldHeader in mapping) {
1090
+ renamedSample[mapping[oldHeader]] = sample[oldHeader];
1091
+ }
1092
+
1093
+ previewText = JSON.stringify(renamedSample, null, 2);
1094
+ }
1095
+ else if (selectedPreset === 'custom') {
1096
+ const template = document.getElementById('custom-template').value.trim();
1097
+ if (template) {
1098
+ try {
1099
+ const sample = getSampleData(1)[0];
1100
+ let result = template;
1101
+
1102
+ // Replace placeholders with actual values
1103
+ for (const key in sample) {
1104
+ const placeholder = `{{${key}}}`;
1105
+ if (template.includes(placeholder)) {
1106
+ result = result.replace(new RegExp(placeholder, 'g'), sample[key]);
1107
+ }
1108
+ }
1109
+
1110
+ previewText = result;
1111
+ } catch (e) {
1112
+ previewText = 'Error applying template. Check your syntax.';
1113
+ }
1114
+ } else {
1115
+ previewText = 'Enter a custom template to see a preview';
1116
+ }
1117
+ }
1118
+
1119
+ previewContent.innerHTML = `<pre class="text-gray-800">${escapeHtml(previewText)}</pre>`;
1120
+ }
1121
+ // If using custom settings tab
1122
+ else {
1123
+ const selectedFormat = document.querySelector('input[name="format"]:checked').value;
1124
+ let previewText = '';
1125
+
1126
+ if (selectedFormat === 'json') {
1127
+ const sample = getSampleData(3);
1128
+ previewText = JSON.stringify(sample, null, 2);
1129
+ } else if (selectedFormat === 'csv') {
1130
+ const newHeaders = getNewHeaders();
1131
+ previewText = newHeaders.join(',') + '\n';
1132
+
1133
+ const sample = getSampleData(3);
1134
+ sample.forEach(row => {
1135
+ const values = newHeaders.map(h => row[h] || '');
1136
+ previewText += values.join(',') + '\n';
1137
+ });
1138
+ }
1139
+
1140
+ previewContent.innerHTML = `<pre class="text-gray-800">${escapeHtml(previewText)}</pre>`;
1141
+ }
1142
+ }
1143
+
1144
+ function getSampleData(count) {
1145
+ return parsedData.slice(0, Math.min(count, parsedData.length));
1146
+ }
1147
+
1148
+ function getNewHeaders() {
1149
+ const inputs = document.querySelectorAll('.header-input');
1150
+ const newHeaders = [];
1151
+
1152
+ inputs.forEach(input => {
1153
+ newHeaders.push(input.value || input.dataset.original);
1154
+ });
1155
+
1156
+ return newHeaders;
1157
+ }
1158
+
1159
+ function getHeaderMapping() {
1160
+ const inputs = document.querySelectorAll('.header-input');
1161
+ const mapping = {};
1162
+
1163
+ inputs.forEach(input => {
1164
+ mapping[input.dataset.original] = input.value || input.dataset.original;
1165
+ });
1166
+
1167
+ return mapping;
1168
+ }
1169
+
1170
+ function convertData() {
1171
+ // If using presets tab
1172
+ if (presetsSection.classList.contains('active') && selectedPreset) {
1173
+ if (selectedPreset === 'chat') {
1174
+ const userCol = document.getElementById('chat-user-col').value;
1175
+ const assistantCol = document.getElementById('chat-assistant-col').value;
1176
+ const systemMsg = document.getElementById('chat-system-msg').value;
1177
+
1178
+ if (userCol && assistantCol) {
1179
+ convertedData = parsedData.map(row => {
1180
+ const messages = [
1181
+ systemMsg ? {role: "system", content: systemMsg} : null,
1182
+ {role: "user", content: row[userCol]},
1183
+ {role: "assistant", content: row[assistantCol]}
1184
+ ].filter(Boolean);
1185
+ return {messages};
1186
+ });
1187
+ }
1188
+ }
1189
+ else if (selectedPreset === 'instruction') {
1190
+ const instructionCol = document.getElementById('instruction-col').value;
1191
+ const responseCol = document.getElementById('response-col').value;
1192
+
1193
+ if (instructionCol && responseCol) {
1194
+ convertedData = parsedData.map(row => ({
1195
+ instruction: row[instructionCol],
1196
+ response: row[responseCol]
1197
+ }));
1198
+ }
1199
+ }
1200
+ else if (selectedPreset === 'qa') {
1201
+ const questionCol = document.getElementById('question-col').value;
1202
+ const answerCol = document.getElementById('answer-col').value;
1203
+
1204
+ if (questionCol && answerCol) {
1205
+ convertedData = parsedData.map(row => ({
1206
+ question: row[questionCol],
1207
+ answer: row[answerCol]
1208
+ }));
1209
+ }
1210
+ }
1211
+ else if (selectedPreset === 'completion') {
1212
+ const promptCol = document.getElementById('prompt-col').value;
1213
+ const completionCol = document.getElementById('completion-col').value;
1214
+
1215
+ if (promptCol && completionCol) {
1216
+ convertedData = parsedData.map(row => ({
1217
+ prompt: row[promptCol],
1218
+ completion: row[completionCol]
1219
+ }));
1220
+ }
1221
+ }
1222
+ else if (selectedPreset === 'rename') {
1223
+ const inputs = document.querySelectorAll('.rename-input');
1224
+ const mapping = {};
1225
+
1226
+ inputs.forEach(input => {
1227
+ mapping[input.dataset.original] = input.value || input.dataset.original;
1228
+ });
1229
+
1230
+ convertedData = parsedData.map(row => {
1231
+ const newRow = {};
1232
+ for (const oldHeader in mapping) {
1233
+ newRow[mapping[oldHeader]] = row[oldHeader];
1234
+ }
1235
+ return newRow;
1236
+ });
1237
+ }
1238
+ else if (selectedPreset === 'custom') {
1239
+ const template = document.getElementById('custom-template').value.trim();
1240
+ if (template) {
1241
+ try {
1242
+ convertedData = parsedData.map(row => {
1243
+ let result = template;
1244
+ for (const key in row) {
1245
+ const placeholder = `{{${key}}}`;
1246
+ if (template.includes(placeholder)) {
1247
+ result = result.replace(new RegExp(placeholder, 'g'), row[key]);
1248
+ }
1249
+ }
1250
+ return result;
1251
+ }).join('\n');
1252
+ } catch (e) {
1253
+ convertedData = 'Error in custom template: ' + e.message;
1254
+ }
1255
+ } else {
1256
+ convertedData = 'No custom template provided';
1257
+ }
1258
+ }
1259
+ }
1260
+ // If using custom settings tab
1261
+ else {
1262
+ const selectedFormat = document.querySelector('input[name="format"]:checked').value;
1263
+ const headerMapping = getHeaderMapping();
1264
+
1265
+ if (selectedFormat === 'json') {
1266
+ // Simple renaming of headers
1267
+ convertedData = parsedData.map(row => {
1268
+ const newRow = {};
1269
+ for (const oldHeader in headerMapping) {
1270
+ newRow[headerMapping[oldHeader]] = row[oldHeader];
1271
+ }
1272
+ return newRow;
1273
+ });
1274
+ } else if (selectedFormat === 'csv') {
1275
+ const newHeaders = Object.values(headerMapping);
1276
+ let csvContent = newHeaders.join(',') + '\n';
1277
+
1278
+ parsedData.forEach(row => {
1279
+ const values = newHeaders.map(h => {
1280
+ // Find the original header that maps to this new header
1281
+ const originalHeader = Object.keys(headerMapping).find(key => headerMapping[key] === h);
1282
+ return row[originalHeader] || '';
1283
+ });
1284
+ csvContent += values.join(',') + '\n';
1285
+ });
1286
+
1287
+ convertedData = csvContent;
1288
+ }
1289
+ }
1290
+ }
1291
+
1292
+ function displayFinalPreview() {
1293
+ if (!convertedData) return;
1294
+
1295
+ if (typeof convertedData === 'string') {
1296
+ finalPreview.innerHTML = `<pre class="text-gray-800">${escapeHtml(convertedData)}</pre>`;
1297
+ } else {
1298
+ finalPreview.innerHTML = `<pre class="text-gray-800">${escapeHtml(JSON.stringify(convertedData, null, 2))}</pre>`;
1299
+ }
1300
+ }
1301
+
1302
+ function downloadConvertedData() {
1303
+ if (!convertedData) return;
1304
+
1305
+ let blob, filename;
1306
+
1307
+ if (typeof convertedData === 'string') {
1308
+ blob = new Blob([convertedData], { type: 'text/csv' });
1309
+ filename = 'converted_data.csv';
1310
+ } else {
1311
+ const dataStr = JSON.stringify(convertedData, null, 2);
1312
+ blob = new Blob([dataStr], { type: 'application/json' });
1313
+ filename = 'converted_data.json';
1314
+ }
1315
+
1316
+ const url = URL.createObjectURL(blob);
1317
+ const a = document.createElement('a');
1318
+ a.href = url;
1319
+ a.download = filename;
1320
+ document.body.appendChild(a);
1321
+ a.click();
1322
+ document.body.removeChild(a);
1323
+ URL.revokeObjectURL(url);
1324
+ }
1325
+
1326
+ function copyToClipboard() {
1327
+ if (!convertedData) return;
1328
+
1329
+ let textToCopy;
1330
+ if (typeof convertedData === 'string') {
1331
+ textToCopy = convertedData;
1332
+ } else {
1333
+ textToCopy = JSON.stringify(convertedData, null, 2);
1334
+ }
1335
+
1336
+ navigator.clipboard.writeText(textToCopy).then(() => {
1337
+ const originalText = copyClipboardBtn.innerHTML;
1338
+ copyClipboardBtn.innerHTML = '<i class="fas fa-check mr-2"></i> Copied!';
1339
+ setTimeout(() => {
1340
+ copyClipboardBtn.innerHTML = originalText;
1341
+ }, 2000);
1342
+ }).catch(err => {
1343
+ console.error('Failed to copy: ', err);
1344
+ alert('Failed to copy to clipboard');
1345
+ });
1346
+ }
1347
+
1348
+ function resetConverter() {
1349
+ uploadedFile = null;
1350
+ parsedData = null;
1351
+ headers = [];
1352
+ convertedData = null;
1353
+ selectedPreset = null;
1354
+
1355
+ fileUpload.value = '';
1356
+ nextStep1Btn.disabled = true;
1357
+
1358
+ headerMappingContainer.innerHTML = `
1359
+ <div class="text-center py-8 text-gray-400">
1360
+ <i class="fas fa-table fa-2x mb-2"></i>
1361
+ <p>Upload a file to see available headers</p>
1362
+ </div>
1363
+ `;
1364
+
1365
+ previewContent.innerHTML = `
1366
+ <div class="text-center py-8 text-gray-400">
1367
+ <i class="fas fa-eye fa-2x mb-2"></i>
1368
+ <p>Configure settings to see a preview</p>
1369
+ </div>
1370
+ `;
1371
+
1372
+ finalPreview.innerHTML = '';
1373
+
1374
+ // Reset dropzone appearance
1375
+ dropzone.classList.remove('active', 'error', 'success');
1376
+ uploadIcon.innerHTML = '<i class="fas fa-cloud-upload-alt text-indigo-500 text-2xl"></i>';
1377
+ dropzoneTitle.textContent = 'Drag & drop your file here';
1378
+ dropzoneSubtitle.classList.remove('hidden');
1379
+ progressContainer.classList.add('hidden');
1380
+ fileInfo.style.display = 'none';
1381
+ hideError();
1382
+
1383
+ // Reset preset selection
1384
+ presetCards.forEach(card => {
1385
+ card.classList.remove('selected', 'border-indigo-500');
1386
+ card.classList.add('border-gray-200');
1387
+ });
1388
+ presetConfig.classList.add('hidden');
1389
+
1390
+ // Reset tabs to presets
1391
+ tabButtons.forEach((btn, index) => {
1392
+ if (index === 0) {
1393
+ btn.classList.add('active', 'text-indigo-600');
1394
+ btn.classList.remove('text-gray-500');
1395
+ } else {
1396
+ btn.classList.remove('active', 'text-indigo-600');
1397
+ btn.classList.add('text-gray-500');
1398
+ }
1399
+ });
1400
+ presetsSection.classList.add('active');
1401
+ customSection.classList.remove('active');
1402
+ }
1403
+
1404
+ function updateStepNavigation(step) {
1405
+ const steps = document.querySelectorAll('.flex.border-b.border-gray-200 > div');
1406
+ steps.forEach((stepEl, index) => {
1407
+ if (index + 1 === step) {
1408
+ stepEl.classList.remove('border-gray-200', 'text-gray-500');
1409
+ stepEl.classList.add('border-indigo-500', 'text-indigo-600');
1410
+ } else {
1411
+ stepEl.classList.remove('border-indigo-500', 'text-indigo-600');
1412
+ stepEl.classList.add('border-gray-200', 'text-gray-500');
1413
+ }
1414
+ });
1415
+ }
1416
+
1417
+ function escapeHtml(unsafe) {
1418
+ return unsafe
1419
+ .replace(/&/g, "&amp;")
1420
+ .replace(/</g, "&lt;")
1421
+ .replace(/>/g, "&gt;")
1422
+ .replace(/"/g, "&quot;")
1423
+ .replace(/'/g, "&#039;");
1424
+ }
1425
+ </script>
1426
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=CultriX/deepsite" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
1427
+ </html>
prompts.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ It needs an easier user interface for (re)formatting or transforming the dataset. Maybe some presets would be useful.