Allanatrix commited on
Commit
7917ec8
·
verified ·
1 Parent(s): f93557b

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +320 -147
app.py CHANGED
@@ -1,147 +1,320 @@
1
- import gradio as gr
2
- import time
3
-
4
- def calculate_price(payment_mode, tokens, plan, custom_price, file):
5
- if payment_mode == "Pay as you go":
6
- price = round(tokens * 0.01, 2) # Example: $0.01 per token
7
- return f"{tokens:,} tokens\nPrice: ${price:.2f}", price
8
- elif payment_mode == "Plan":
9
- if plan == "Free":
10
- return "0 tokens\nPrice: $0", 0
11
- elif plan == "Starter":
12
- return "100,000 tokens\nPrice: $15", 15
13
- elif plan == "Pro":
14
- return "500,000 tokens\nPrice: $30", 30
15
- elif plan == "Custom":
16
- return f"Custom plan\nPrice: ${custom_price}", float(custom_price or 0)
17
- elif file is not None:
18
- # Simulate token count from file size
19
- tokens = 1000 # Replace it with real calculation
20
- price = round(tokens * 0.01, 2)
21
- return f"{tokens:,} tokens\nPrice: ${price:.2f}", price
22
- return "", 0
23
-
24
- def generate_dataset(*args, **kwargs):
25
- for i in range(5):
26
- yield f"Generating... ({(i+1)*20}%)", None, (i+1)/5
27
- time.sleep(0.3)
28
- yield "Ready! Please pay to download.", "dataset.jsonl", 1.0
29
-
30
- with gr.Blocks(
31
- title="Nexa Data Studio",
32
- css="""
33
- body, .gradio-container {
34
- min-height: 100vh;
35
- background: #111 !important;
36
- color: #fff !important;
37
- }
38
- .gradio-container {
39
- max-width: 900px !important;
40
- margin: 40px auto !important;
41
- box-shadow: 0 2px 16px #0008;
42
- border-radius: 16px;
43
- padding: 32px 32px 24px 32px !important;
44
- background: #111 !important;
45
- color: #fff !important;
46
- display: flex;
47
- flex-direction: column;
48
- align-items: center;
49
- }
50
- .footer {margin-top: 2em; color: #bbb; font-size: 0.9em; text-align: center;}
51
- #header {text-align: center;}
52
- """
53
- ) as demo:
54
- gr.Markdown(
55
- """
56
- <div style="display:flex;align-items:center;gap:16px;justify-content:center;">
57
- <img src="https://huggingface.co/front/assets/huggingface_logo-noborder.svg" height="40"/>
58
- <h1 style="margin-bottom:0;">Nexa Data Studio</h1>
59
- </div>
60
- <p style="text-align:center;">
61
- <b>Generate or label scientific datasets for ML research.</b>
62
- </p>
63
- """,
64
- elem_id="header"
65
- )
66
-
67
- payment_mode = gr.Radio(
68
- ["Pay as you go", "Plan"],
69
- label="Payment Mode",
70
- value="Pay as you go"
71
- )
72
-
73
- with gr.Row() as payg_row:
74
- tokens = gr.Slider(100, 100000, value=1000, step=100, label="Tokens Requested")
75
- with gr.Row(visible=False) as plan_row:
76
- plan = gr.Dropdown(
77
- ["Free", "Starter", "Pro", "Custom"],
78
- label="Plan",
79
- value="Free"
80
- )
81
- custom_price = gr.Number(label="Custom Price ($)", visible=False)
82
-
83
- job_type = gr.Radio(
84
- ["Generate Dataset", "Label Uploaded Data"],
85
- label="Job Type",
86
- value="Generate Dataset"
87
- )
88
-
89
- with gr.Column(visible=False) as label_col:
90
- file = gr.File(label="Upload Dataset (.txt or .jsonl)")
91
-
92
- price_info = gr.Textbox(label="Summary", interactive=False)
93
- download = gr.File(label="Download")
94
- progress = gr.Slider(0, 1, value=0, step=0.01, label="Progress", interactive=False)
95
- status = gr.Text(label="Status", interactive=False)
96
-
97
- def update_payment_ui(payment_mode_val, plan_val):
98
- return (
99
- gr.update(visible=payment_mode_val == "Pay as you go"),
100
- gr.update(visible=payment_mode_val == "Plan"),
101
- gr.update(visible=payment_mode_val == "Plan" and plan_val == "Custom")
102
- )
103
-
104
- payment_mode.change(
105
- update_payment_ui,
106
- inputs=[payment_mode, plan],
107
- outputs=[payg_row, plan_row, custom_price]
108
- )
109
- plan.change(
110
- lambda p: gr.update(visible=p == "Custom"),
111
- inputs=plan,
112
- outputs=custom_price
113
- )
114
-
115
- def update_label_ui(job_type_val):
116
- return gr.update(visible=job_type_val == "Label Uploaded Data")
117
- job_type.change(update_label_ui, inputs=job_type, outputs=label_col)
118
-
119
- def update_summary(payment_mode, tokens, plan, custom_price, file, job_type):
120
- if job_type == "Label Uploaded Data" and file is not None:
121
- return calculate_price("Label", tokens, plan, custom_price, file)[0]
122
- return calculate_price(payment_mode, tokens, plan, custom_price, file)[0]
123
-
124
- inputs = [payment_mode, tokens, plan, custom_price, file, job_type]
125
- gr.Button("Generate", elem_id="generate-btn", variant="primary").click(
126
- generate_dataset,
127
- inputs=inputs,
128
- outputs=[status, download, progress]
129
- )
130
- gr.Button("Update Summary").click(
131
- update_summary,
132
- inputs=inputs,
133
- outputs=price_info
134
- )
135
-
136
- gr.Markdown(
137
- f"""
138
- <div class="footer">
139
- &copy; {time.strftime("%Y")} Nexa Data Studio &mdash; Powered by Hugging Face Spaces<br>
140
- For support, contact <a href="mailto:support@nexadatastudio.com">support@nexadatastudio.com</a>
141
- </div>
142
- """
143
- )
144
-
145
- if __name__ == "__main__":
146
- demo.launch(server_name="0.0.0.0", server_port=7860, show_error=True)
147
- print("Nexa Data Studio is running at http://localhost:7860")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Nexa Data Studio — Scientific Dataset Generator
3
+ Aethron Labs | No payment required, fully functional synthetic data generation.
4
+ """
5
+
6
+ import gradio as gr
7
+ import json
8
+ import csv
9
+ import io
10
+ import random
11
+ import math
12
+ import time
13
+ import tempfile
14
+ import os
15
+ from datetime import datetime
16
+
17
+ # ── Synthetic data generators ──────────────────────────────────────────────
18
+
19
+ def _gaussian_noise(n, dim, noise=0.05):
20
+ return [[round(random.gauss(0, 1) + random.gauss(0, noise), 4) for _ in range(dim)] for _ in range(n)]
21
+
22
+ def generate_regression(n_samples, n_features, noise_level, seed):
23
+ random.seed(seed)
24
+ records = []
25
+ weights = [random.uniform(-2, 2) for _ in range(n_features)]
26
+ for i in range(n_samples):
27
+ x = [round(random.gauss(0, 1), 4) for _ in range(n_features)]
28
+ y = sum(w * xi for w, xi in zip(weights, x)) + random.gauss(0, noise_level)
29
+ records.append({f"x{j+1}": x[j] for j in range(n_features)} | {"y": round(y, 4), "sample_id": i})
30
+ return records
31
+
32
+ def generate_classification(n_samples, n_classes, n_features, noise_level, seed):
33
+ random.seed(seed)
34
+ records = []
35
+ centers = [[random.uniform(-4, 4) for _ in range(n_features)] for _ in range(n_classes)]
36
+ for i in range(n_samples):
37
+ cls = random.randint(0, n_classes - 1)
38
+ x = [round(centers[cls][j] + random.gauss(0, 1 + noise_level), 4) for j in range(n_features)]
39
+ records.append({f"x{j+1}": x[j] for j in range(n_features)} | {"label": cls, "sample_id": i})
40
+ return records
41
+
42
+ def generate_timeseries(n_samples, n_series, noise_level, seed):
43
+ random.seed(seed)
44
+ records = []
45
+ for s in range(n_series):
46
+ freq = random.uniform(0.05, 0.3)
47
+ amp = random.uniform(0.5, 2.0)
48
+ phase = random.uniform(0, 2 * math.pi)
49
+ for t in range(n_samples):
50
+ val = amp * math.sin(2 * math.pi * freq * t + phase) + random.gauss(0, noise_level)
51
+ records.append({"series_id": s, "timestep": t, "value": round(val, 4)})
52
+ return records
53
+
54
+ def generate_molecular(n_samples, seed):
55
+ random.seed(seed)
56
+ elements = ["C", "H", "O", "N", "S", "P", "F", "Cl"]
57
+ records = []
58
+ for i in range(n_samples):
59
+ n_atoms = random.randint(5, 20)
60
+ formula = "".join(
61
+ f"{e}{random.randint(1,6)}" for e in random.sample(elements, random.randint(2, 4))
62
+ )
63
+ mw = round(random.uniform(50, 500), 2)
64
+ logp = round(random.gauss(2.0, 1.5), 3)
65
+ tpsa = round(random.uniform(20, 150), 2)
66
+ hbd = random.randint(0, 5)
67
+ hba = random.randint(0, 10)
68
+ records.append({
69
+ "sample_id": i, "formula": formula, "n_atoms": n_atoms,
70
+ "mol_weight": mw, "logP": logp, "TPSA": tpsa,
71
+ "HBD": hbd, "HBA": hba,
72
+ "lipinski_pass": int(mw <= 500 and logp <= 5 and hbd <= 5 and hba <= 10)
73
+ })
74
+ return records
75
+
76
+ def generate_pde_field(n_samples, grid_size, noise_level, seed):
77
+ random.seed(seed)
78
+ records = []
79
+ for i in range(n_samples):
80
+ kx = random.uniform(0.5, 3.0)
81
+ ky = random.uniform(0.5, 3.0)
82
+ for gx in range(grid_size):
83
+ for gy in range(grid_size):
84
+ x = gx / grid_size
85
+ y = gy / grid_size
86
+ u = math.sin(kx * math.pi * x) * math.cos(ky * math.pi * y) + random.gauss(0, noise_level)
87
+ records.append({"sample_id": i, "x": round(x, 3), "y": round(y, 3), "u": round(u, 4)})
88
+ return records
89
+
90
+ # ── File writers ────────────────────────────────────────────────────────────
91
+
92
+ def records_to_jsonl(records):
93
+ return "\n".join(json.dumps(r) for r in records)
94
+
95
+ def records_to_csv(records):
96
+ if not records:
97
+ return ""
98
+ buf = io.StringIO()
99
+ writer = csv.DictWriter(buf, fieldnames=records[0].keys())
100
+ writer.writeheader()
101
+ writer.writerows(records)
102
+ return buf.getvalue()
103
+
104
+ def save_to_tmp(content, ext):
105
+ tmp = tempfile.NamedTemporaryFile(delete=False, suffix=f".{ext}", mode="w")
106
+ tmp.write(content)
107
+ tmp.close()
108
+ return tmp.name
109
+
110
+ # ── Main generation function ────────────────────────────────────────────────
111
+
112
+ def run_generation(dataset_type, n_samples, n_features, n_classes, n_series,
113
+ grid_size, noise_level, seed, output_format, progress=gr.Progress()):
114
+
115
+ progress(0, desc="Initialising...")
116
+ time.sleep(0.2)
117
+ progress(0.2, desc="Generating samples...")
118
+
119
+ try:
120
+ if dataset_type == "Regression":
121
+ records = generate_regression(int(n_samples), int(n_features), float(noise_level), int(seed))
122
+ elif dataset_type == "Classification":
123
+ records = generate_classification(int(n_samples), int(n_classes), int(n_features), float(noise_level), int(seed))
124
+ elif dataset_type == "Time Series":
125
+ records = generate_timeseries(int(n_samples), int(n_series), float(noise_level), int(seed))
126
+ elif dataset_type == "Molecular Properties":
127
+ records = generate_molecular(int(n_samples), int(seed))
128
+ elif dataset_type == "PDE Field (2D)":
129
+ records = generate_pde_field(int(n_samples), int(grid_size), float(noise_level), int(seed))
130
+ else:
131
+ return "Unknown dataset type.", None, ""
132
+
133
+ progress(0.7, desc="Serialising output...")
134
+ time.sleep(0.1)
135
+
136
+ if output_format == "JSONL":
137
+ content = records_to_jsonl(records)
138
+ ext = "jsonl"
139
+ else:
140
+ content = records_to_csv(records)
141
+ ext = "csv"
142
+
143
+ progress(0.9, desc="Writing file...")
144
+ filepath = save_to_tmp(content, ext)
145
+
146
+ progress(1.0, desc="Done!")
147
+ preview = "\n".join(json.dumps(r) for r in records[:5])
148
+ status = (
149
+ f"Generated {len(records):,} records · {dataset_type} · "
150
+ f"{output_format} · seed={seed} · {datetime.utcnow().strftime('%H:%M:%S UTC')}"
151
+ )
152
+ return status, filepath, preview
153
+
154
+ except Exception as e:
155
+ return f"Error: {e}", None, ""
156
+
157
+ # ── Label uploaded data ─────────────────────────────────────────────────────
158
+
159
+ def label_uploaded(file, label_col_name, n_classes, seed, progress=gr.Progress()):
160
+ if file is None:
161
+ return "No file uploaded.", None, ""
162
+
163
+ progress(0, desc="Reading file...")
164
+ try:
165
+ with open(file.name, "r") as f:
166
+ first_line = f.readline().strip()
167
+ # Detect JSONL vs CSV
168
+ try:
169
+ json.loads(first_line)
170
+ is_jsonl = True
171
+ except Exception:
172
+ is_jsonl = False
173
+
174
+ records = []
175
+ with open(file.name, "r") as f:
176
+ if is_jsonl:
177
+ for line in f:
178
+ line = line.strip()
179
+ if line:
180
+ records.append(json.loads(line))
181
+ else:
182
+ reader = csv.DictReader(f)
183
+ records = list(reader)
184
+
185
+ progress(0.5, desc="Assigning labels...")
186
+ random.seed(seed)
187
+ for r in records:
188
+ r[label_col_name] = random.randint(0, int(n_classes) - 1)
189
+
190
+ progress(0.85, desc="Writing output...")
191
+ content = records_to_jsonl(records) if is_jsonl else records_to_csv(records)
192
+ ext = "jsonl" if is_jsonl else "csv"
193
+ filepath = save_to_tmp(content, ext)
194
+
195
+ progress(1.0, desc="Done!")
196
+ preview = "\n".join(json.dumps(r) for r in records[:5])
197
+ status = f"Labelled {len(records):,} records with {n_classes} classes → column '{label_col_name}'"
198
+ return status, filepath, preview
199
+
200
+ except Exception as e:
201
+ return f"Error: {e}", None, ""
202
+
203
+ # ── Gradio UI ───────────────────────────────────────────────────────────────
204
+
205
+ CSS = """
206
+ body, .gradio-container { background: #070a12 !important; color: #e8eaf6 !important; }
207
+ .gradio-container { max-width: 960px !important; margin: 0 auto !important; }
208
+ h1, h2, h3 { font-family: 'Space Mono', monospace !important; }
209
+ .gr-button-primary { background: #7c5cfc !important; border-color: #7c5cfc !important; }
210
+ .gr-button-primary:hover { background: #9b7ffe !important; }
211
+ footer { display: none !important; }
212
+ """
213
+
214
+ with gr.Blocks(title="Nexa Data Studio", css=CSS, theme=gr.themes.Base()) as demo:
215
+
216
+ gr.Markdown("""
217
+ # ⬡ Nexa Data Studio
218
+ **Scientific Dataset Generator** · Aethron Labs
219
+ Generate synthetic datasets for ML research — regression, classification, time series, molecular, and PDE fields. No payment required.
220
+ ---
221
+ """)
222
+
223
+ with gr.Tabs():
224
+
225
+ # ── TAB 1: Generate ──────────────────────────────────────────────
226
+ with gr.TabItem("Generate Dataset"):
227
+ with gr.Row():
228
+ with gr.Column(scale=1):
229
+ dataset_type = gr.Dropdown(
230
+ ["Regression", "Classification", "Time Series", "Molecular Properties", "PDE Field (2D)"],
231
+ label="Dataset Type", value="Regression"
232
+ )
233
+ n_samples = gr.Slider(50, 5000, value=500, step=50, label="Number of Samples")
234
+ output_format = gr.Radio(["JSONL", "CSV"], value="JSONL", label="Output Format")
235
+ noise_level = gr.Slider(0.0, 2.0, value=0.1, step=0.05, label="Noise Level (σ)")
236
+ seed = gr.Number(value=42, label="Random Seed", precision=0)
237
+
238
+ with gr.Column(scale=1):
239
+ with gr.Group() as reg_cls_opts:
240
+ n_features = gr.Slider(1, 20, value=4, step=1, label="Number of Features")
241
+ with gr.Group(visible=False) as cls_opts:
242
+ n_classes = gr.Slider(2, 10, value=3, step=1, label="Number of Classes")
243
+ with gr.Group(visible=False) as ts_opts:
244
+ n_series = gr.Slider(1, 20, value=3, step=1, label="Number of Series")
245
+ with gr.Group(visible=False) as pde_opts:
246
+ grid_size = gr.Slider(4, 32, value=8, step=2, label="Grid Size (NxN)")
247
+
248
+ def update_opts(dtype):
249
+ show_feat = dtype in ["Regression", "Classification"]
250
+ show_cls = dtype == "Classification"
251
+ show_ts = dtype == "Time Series"
252
+ show_pde = dtype == "PDE Field (2D)"
253
+ return (
254
+ gr.update(visible=show_feat),
255
+ gr.update(visible=show_cls),
256
+ gr.update(visible=show_ts),
257
+ gr.update(visible=show_pde),
258
+ )
259
+
260
+ dataset_type.change(update_opts, dataset_type, [reg_cls_opts, cls_opts, ts_opts, pde_opts])
261
+
262
+ gen_btn = gr.Button("Generate Dataset", variant="primary")
263
+ gen_status = gr.Textbox(label="Status", interactive=False)
264
+ gen_file = gr.File(label="Download Generated Dataset")
265
+ gen_preview = gr.Code(label="Preview (first 5 records)", language="json", lines=8)
266
+
267
+ gen_btn.click(
268
+ run_generation,
269
+ inputs=[dataset_type, n_samples, n_features, n_classes, n_series, grid_size, noise_level, seed, output_format],
270
+ outputs=[gen_status, gen_file, gen_preview]
271
+ )
272
+
273
+ # ── TAB 2: Label Uploaded Data ───────────────────────────────────
274
+ with gr.TabItem("Label Uploaded Data"):
275
+ gr.Markdown("Upload an existing `.jsonl` or `.csv` file and automatically assign random class labels to each record.")
276
+ with gr.Row():
277
+ with gr.Column():
278
+ upload_file = gr.File(label="Upload Dataset (.jsonl or .csv)", file_types=[".jsonl", ".csv"])
279
+ label_col = gr.Textbox(value="label", label="Label Column Name")
280
+ label_classes = gr.Slider(2, 20, value=3, step=1, label="Number of Classes")
281
+ label_seed = gr.Number(value=42, label="Random Seed", precision=0)
282
+ label_btn = gr.Button("Assign Labels", variant="primary")
283
+
284
+ label_status = gr.Textbox(label="Status", interactive=False)
285
+ label_file = gr.File(label="Download Labelled Dataset")
286
+ label_preview = gr.Code(label="Preview (first 5 records)", language="json", lines=8)
287
+
288
+ label_btn.click(
289
+ label_uploaded,
290
+ inputs=[upload_file, label_col, label_classes, label_seed],
291
+ outputs=[label_status, label_file, label_preview]
292
+ )
293
+
294
+ # ── TAB 3: About ─────────────────────────────────────────────────
295
+ with gr.TabItem("About"):
296
+ gr.Markdown("""
297
+ ## Nexa Data Studio
298
+
299
+ Part of the **Nexa Stack** by [Aethron Labs](https://huggingface.co/AethronPhantom) — a Scientific Machine Learning Research Lab.
300
+
301
+ ### Supported Dataset Types
302
+
303
+ | Type | Description | Use Case |
304
+ |------|-------------|----------|
305
+ | **Regression** | Continuous target from linear combination of features + noise | Surrogate model training |
306
+ | **Classification** | Gaussian cluster data with configurable classes | Classifier benchmarking |
307
+ | **Time Series** | Multi-series sinusoidal signals with noise | Forecasting, anomaly detection |
308
+ | **Molecular Properties** | Synthetic molecular descriptors (MW, logP, TPSA, HBD/HBA) | Drug discovery ML |
309
+ | **PDE Field (2D)** | 2D sinusoidal field solutions with noise | Physics-informed neural networks |
310
+
311
+ ### Output Formats
312
+ - **JSONL** — one JSON object per line, ideal for streaming and LLM fine-tuning pipelines
313
+ - **CSV** — tabular format for pandas, sklearn, and spreadsheet tools
314
+
315
+ ### Notes
316
+ All data is synthetically generated — no real molecular structures or physical measurements are included.
317
+ For research use only.
318
+ """)
319
+
320
+ demo.launch()