featrixsphere 0.2.1233__py3-none-any.whl → 0.2.1237__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- featrixsphere/__init__.py +1 -1
- featrixsphere/client.py +111 -78
- {featrixsphere-0.2.1233.dist-info → featrixsphere-0.2.1237.dist-info}/METADATA +1 -1
- featrixsphere-0.2.1237.dist-info/RECORD +9 -0
- featrixsphere-0.2.1233.dist-info/RECORD +0 -9
- {featrixsphere-0.2.1233.dist-info → featrixsphere-0.2.1237.dist-info}/WHEEL +0 -0
- {featrixsphere-0.2.1233.dist-info → featrixsphere-0.2.1237.dist-info}/entry_points.txt +0 -0
- {featrixsphere-0.2.1233.dist-info → featrixsphere-0.2.1237.dist-info}/top_level.txt +0 -0
featrixsphere/__init__.py
CHANGED
featrixsphere/client.py
CHANGED
|
@@ -4194,93 +4194,126 @@ class FeatrixSphereClient:
|
|
|
4194
4194
|
print(f"Training predictor on foundation model {foundation_model_id}...")
|
|
4195
4195
|
print(f" Target: {target_column} ({target_column_type})")
|
|
4196
4196
|
|
|
4197
|
-
#
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
if
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
if not isinstance(df, pd.DataFrame):
|
|
4209
|
-
raise ValueError("df must be a pandas DataFrame")
|
|
4210
|
-
|
|
4197
|
+
# Get the compute cluster from the foundation model session
|
|
4198
|
+
# This ensures we upload files to the same node where the foundation model lives
|
|
4199
|
+
foundation_session = self.get_session_status(foundation_model_id)
|
|
4200
|
+
foundation_compute_cluster = self.get_last_server_metadata()
|
|
4201
|
+
foundation_compute_cluster = foundation_compute_cluster.get('compute_cluster') if foundation_compute_cluster else None
|
|
4202
|
+
|
|
4203
|
+
# Temporarily set compute cluster for file uploads if we found one
|
|
4204
|
+
original_compute_cluster = self.compute_cluster
|
|
4205
|
+
original_headers = self.session.headers.copy()
|
|
4206
|
+
if foundation_compute_cluster:
|
|
4207
|
+
self.set_compute_cluster(foundation_compute_cluster)
|
|
4211
4208
|
if verbose:
|
|
4212
|
-
print(f"
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
# Save DataFrame to temp file
|
|
4220
|
-
df.to_csv(temp_file_path, index=False)
|
|
4221
|
-
|
|
4222
|
-
if verbose:
|
|
4223
|
-
print(f"📁 Saved to temporary file: {os.path.basename(temp_file_path)}")
|
|
4224
|
-
print(f"📤 Uploading file to server...")
|
|
4225
|
-
|
|
4226
|
-
# Upload the file
|
|
4227
|
-
uploaded_filename = self.upload_file(temp_file_path)
|
|
4228
|
-
input_filename = uploaded_filename
|
|
4209
|
+
print(f" Using compute cluster: {foundation_compute_cluster}")
|
|
4210
|
+
|
|
4211
|
+
try:
|
|
4212
|
+
# Validate that only one data source is provided
|
|
4213
|
+
if input_filename and df is not None:
|
|
4214
|
+
raise ValueError("Provide either input_filename or df, not both")
|
|
4229
4215
|
|
|
4230
|
-
|
|
4231
|
-
|
|
4216
|
+
# Prepare multipart form data (like train_single_predictor_with_file does)
|
|
4217
|
+
files = None
|
|
4218
|
+
data = {
|
|
4219
|
+
"foundation_model_id": foundation_model_id,
|
|
4220
|
+
"target_column": target_column,
|
|
4221
|
+
"target_column_type": target_column_type,
|
|
4222
|
+
"epochs": str(epochs),
|
|
4223
|
+
"optimize_for": optimize_for,
|
|
4224
|
+
}
|
|
4232
4225
|
|
|
4233
|
-
#
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
"target_column": target_column,
|
|
4242
|
-
"target_column_type": target_column_type,
|
|
4243
|
-
"epochs": epochs,
|
|
4244
|
-
"optimize_for": optimize_for,
|
|
4245
|
-
}
|
|
4246
|
-
|
|
4247
|
-
if input_filename:
|
|
4248
|
-
# If absolute path provided, upload the file first
|
|
4249
|
-
from pathlib import Path
|
|
4250
|
-
input_path = Path(input_filename)
|
|
4251
|
-
if input_path.is_absolute():
|
|
4252
|
-
# Upload the file first, then use the uploaded filename
|
|
4253
|
-
if not input_path.exists():
|
|
4254
|
-
raise FileNotFoundError(f"Input file not found: {input_filename}")
|
|
4226
|
+
# Handle file upload - send file directly in multipart form
|
|
4227
|
+
if df is not None:
|
|
4228
|
+
import pandas as pd
|
|
4229
|
+
import tempfile
|
|
4230
|
+
import os
|
|
4231
|
+
|
|
4232
|
+
if not isinstance(df, pd.DataFrame):
|
|
4233
|
+
raise ValueError("df must be a pandas DataFrame")
|
|
4255
4234
|
|
|
4256
4235
|
if verbose:
|
|
4257
|
-
print(f"
|
|
4236
|
+
print(f"📊 Using provided DataFrame ({len(df)} rows, {len(df.columns)} columns)")
|
|
4237
|
+
|
|
4238
|
+
# Create temporary CSV file
|
|
4239
|
+
temp_file = tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False)
|
|
4240
|
+
temp_file_path = temp_file.name
|
|
4241
|
+
temp_file.close()
|
|
4258
4242
|
|
|
4259
|
-
#
|
|
4260
|
-
|
|
4243
|
+
# Save DataFrame to temp file
|
|
4244
|
+
df.to_csv(temp_file_path, index=False)
|
|
4261
4245
|
|
|
4262
4246
|
if verbose:
|
|
4263
|
-
print(f"
|
|
4247
|
+
print(f"📁 Saved to temporary file: {os.path.basename(temp_file_path)}")
|
|
4248
|
+
print(f"📤 Uploading file directly with training request...")
|
|
4264
4249
|
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4250
|
+
# Send file in multipart form
|
|
4251
|
+
files = {'file': (os.path.basename(temp_file_path), open(temp_file_path, 'rb'), 'text/csv')}
|
|
4252
|
+
|
|
4253
|
+
elif input_filename:
|
|
4254
|
+
# If absolute path provided, send file directly
|
|
4255
|
+
from pathlib import Path
|
|
4256
|
+
input_path = Path(input_filename)
|
|
4257
|
+
if input_path.is_absolute():
|
|
4258
|
+
if not input_path.exists():
|
|
4259
|
+
raise FileNotFoundError(f"Input file not found: {input_filename}")
|
|
4260
|
+
|
|
4261
|
+
if verbose:
|
|
4262
|
+
print(f"📤 Sending file directly from absolute path: {input_filename}")
|
|
4263
|
+
|
|
4264
|
+
# Send file in multipart form
|
|
4265
|
+
files = {'file': (input_path.name, open(input_path, 'rb'), 'text/csv' if input_path.suffix == '.csv' else 'application/gzip')}
|
|
4266
|
+
else:
|
|
4267
|
+
# Relative filename - assume it's already on the server
|
|
4268
|
+
data["input_filename"] = input_filename
|
|
4269
|
+
|
|
4270
|
+
if name:
|
|
4271
|
+
data["name"] = name
|
|
4272
|
+
if session_name_prefix:
|
|
4273
|
+
data["session_name_prefix"] = session_name_prefix
|
|
4274
|
+
if rare_label_value:
|
|
4275
|
+
data["rare_label_value"] = rare_label_value
|
|
4276
|
+
if class_imbalance:
|
|
4277
|
+
import json
|
|
4278
|
+
data["class_imbalance"] = json.dumps(class_imbalance)
|
|
4279
|
+
if webhooks:
|
|
4280
|
+
import json
|
|
4281
|
+
data["webhooks"] = json.dumps(webhooks)
|
|
4282
|
+
|
|
4283
|
+
# Send request with file if provided
|
|
4284
|
+
try:
|
|
4285
|
+
if files:
|
|
4286
|
+
response = self._make_request("POST", "/compute/train_on_foundational_model", files=files, data=data)
|
|
4287
|
+
else:
|
|
4288
|
+
response = self._make_request("POST", "/compute/train_on_foundational_model", json=data)
|
|
4289
|
+
response_data = response.json()
|
|
4290
|
+
finally:
|
|
4291
|
+
# Close file handles
|
|
4292
|
+
if files and 'file' in files:
|
|
4293
|
+
files['file'][1].close()
|
|
4294
|
+
# Clean up temp file if we created one
|
|
4295
|
+
if df is not None and temp_file_path:
|
|
4296
|
+
try:
|
|
4297
|
+
os.unlink(temp_file_path)
|
|
4298
|
+
except Exception:
|
|
4299
|
+
pass
|
|
4300
|
+
|
|
4301
|
+
new_session_id = response_data.get('session_id')
|
|
4302
|
+
print(f"✅ Predictor training session created: {new_session_id}")
|
|
4303
|
+
|
|
4304
|
+
# Restore original compute cluster setting
|
|
4305
|
+
if original_compute_cluster != self.compute_cluster:
|
|
4306
|
+
if original_compute_cluster:
|
|
4307
|
+
self.set_compute_cluster(original_compute_cluster)
|
|
4308
|
+
else:
|
|
4309
|
+
self.session.headers = original_headers
|
|
4310
|
+
finally:
|
|
4311
|
+
# Ensure we restore headers even if there's an error
|
|
4312
|
+
if original_compute_cluster != self.compute_cluster:
|
|
4313
|
+
if original_compute_cluster:
|
|
4314
|
+
self.set_compute_cluster(original_compute_cluster)
|
|
4315
|
+
else:
|
|
4316
|
+
self.session.headers = original_headers
|
|
4284
4317
|
|
|
4285
4318
|
if verbose:
|
|
4286
4319
|
print(f"⏳ Waiting for training to complete...")
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
featrixsphere/__init__.py,sha256=B4omX54pm9GR-ascatiSaHJPIOziXObJlkcE1U5Lte0,1888
|
|
2
|
+
featrixsphere/cli.py,sha256=AW9O3vCvCNJ2UxVGN66eRmeN7XLSiHJlvK6JLZ9UJXc,13358
|
|
3
|
+
featrixsphere/client.py,sha256=5BgOKD0lC1Tsnkj1NsKkx_QMdvQJM3Qn8F6DfQjlCQ8,384584
|
|
4
|
+
featrixsphere/test_client.py,sha256=4SiRbib0ms3poK0UpnUv4G0HFQSzidF3Iswo_J2cjLk,11981
|
|
5
|
+
featrixsphere-0.2.1237.dist-info/METADATA,sha256=UOQ8XXBXkiZzIvATWl8X1xIkcGM8soxDYfs9IzY5u7k,16232
|
|
6
|
+
featrixsphere-0.2.1237.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
+
featrixsphere-0.2.1237.dist-info/entry_points.txt,sha256=QreJeYfD_VWvbEqPmMXZ3pqqlFlJ1qZb-NtqnyhEldc,51
|
|
8
|
+
featrixsphere-0.2.1237.dist-info/top_level.txt,sha256=AyN4wjfzlD0hWnDieuEHX0KckphIk_aC73XCG4df5uU,14
|
|
9
|
+
featrixsphere-0.2.1237.dist-info/RECORD,,
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
featrixsphere/__init__.py,sha256=Iwvv27mlpZjhl7DSUg6kz9Qa24K1S-o5aa-QqwgwcFA,1888
|
|
2
|
-
featrixsphere/cli.py,sha256=AW9O3vCvCNJ2UxVGN66eRmeN7XLSiHJlvK6JLZ9UJXc,13358
|
|
3
|
-
featrixsphere/client.py,sha256=xjYFie7KxepDRp8j8MA0divHyhC_t7fLnjgQUClV0_c,382285
|
|
4
|
-
featrixsphere/test_client.py,sha256=4SiRbib0ms3poK0UpnUv4G0HFQSzidF3Iswo_J2cjLk,11981
|
|
5
|
-
featrixsphere-0.2.1233.dist-info/METADATA,sha256=lQDkfyCT4NMnCnob9Vhgv77YfKrH96XNSoaP0IFpsZM,16232
|
|
6
|
-
featrixsphere-0.2.1233.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
-
featrixsphere-0.2.1233.dist-info/entry_points.txt,sha256=QreJeYfD_VWvbEqPmMXZ3pqqlFlJ1qZb-NtqnyhEldc,51
|
|
8
|
-
featrixsphere-0.2.1233.dist-info/top_level.txt,sha256=AyN4wjfzlD0hWnDieuEHX0KckphIk_aC73XCG4df5uU,14
|
|
9
|
-
featrixsphere-0.2.1233.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|