salesforce-data-customcode 6.0.5.dev1__tar.gz → 6.0.7.dev1__tar.gz
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.
- salesforce_data_customcode-6.0.5.dev1/README.md → salesforce_data_customcode-6.0.7.dev1/PKG-INFO +81 -4
- salesforce_data_customcode-6.0.5.dev1/PKG-INFO → salesforce_data_customcode-6.0.7.dev1/README.md +55 -30
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/pyproject.toml +2 -2
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/__init__.py +15 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/client.py +116 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/config.yaml +3 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/einstein_predictions/__init__.py +8 -0
- salesforce_data_customcode-6.0.7.dev1/src/datacustomcode/einstein_predictions/errors.py +36 -0
- salesforce_data_customcode-6.0.7.dev1/src/datacustomcode/einstein_predictions/spark_base.py +72 -0
- salesforce_data_customcode-6.0.7.dev1/src/datacustomcode/einstein_predictions/spark_default.py +239 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/einstein_predictions_config.py +45 -1
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/script/payload/entrypoint.py +17 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/token_provider.py +12 -9
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/LICENSE.txt +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/auth.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/cli.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/cmd.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/common_config.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/config.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/constants.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/credentials.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/deploy.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/einstein_platform_client.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/einstein_platform_config.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/einstein_predictions/base.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/einstein_predictions/impl/default.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/einstein_predictions/types.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/file/__init__.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/file/base.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/file/path/__init__.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/file/path/default.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/function/__init__.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/function/base.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/function/feature_types/__init__.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/function/feature_types/chunking.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/function/runtime.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/function_utils.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/io/__init__.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/io/base.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/io/reader/__init__.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/io/reader/base.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/io/reader/query_api.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/io/reader/sf_cli.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/io/reader/utils.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/io/writer/__init__.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/io/writer/base.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/io/writer/csv.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/io/writer/print.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/llm_gateway/__init__.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/llm_gateway/base.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/llm_gateway/default.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/llm_gateway/errors.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/llm_gateway/spark_base.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/llm_gateway/spark_default.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/llm_gateway/types/__init__.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/llm_gateway/types/generate_text_request.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/llm_gateway/types/generate_text_request_builder.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/llm_gateway/types/generate_text_response.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/llm_gateway/types/generate_text_response_builder.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/llm_gateway_config.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/mixin.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/py.typed +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/run.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/scan.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/spark/__init__.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/spark/base.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/spark/default.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/template.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/__init__.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/function/.devcontainer/devcontainer.json +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/function/Dockerfile.dependencies +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/function/README.md +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/function/build_native_dependencies.sh +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/function/chunking/payload/config.json +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/function/chunking/payload/entrypoint.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/function/chunking/requirements.txt +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/function/example/chunking_with_llm/config.json +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/function/example/chunking_with_llm/entrypoint.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/function/example/chunking_with_llm/files/chunking_prompt.txt +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/function/example/chunking_with_llm/tests/test.json +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/function/example/chunking_with_prediction/config.json +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/function/example/chunking_with_prediction/entrypoint.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/function/example/chunking_with_prediction/tests/test.json +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/function/payload/config.json +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/function/payload/entrypoint.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/function/payload/utility.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/function/requirements-dev.txt +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/function/requirements.txt +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/script/.devcontainer/devcontainer.json +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/script/Dockerfile +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/script/Dockerfile.dependencies +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/script/README.md +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/script/account.ipynb +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/script/build_native_dependencies.sh +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/script/examples/employee_hierarchy/employee_data.csv +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/script/examples/employee_hierarchy/entrypoint.py +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/script/jupyterlab.sh +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/script/payload/config.json +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/script/requirements-dev.txt +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/templates/script/requirements.txt +0 -0
- {salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/src/datacustomcode/version.py +0 -0
salesforce_data_customcode-6.0.5.dev1/README.md → salesforce_data_customcode-6.0.7.dev1/PKG-INFO
RENAMED
|
@@ -1,4 +1,29 @@
|
|
|
1
|
-
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: salesforce-data-customcode
|
|
3
|
+
Version: 6.0.7.dev1
|
|
4
|
+
Summary: Data Cloud Custom Code SDK
|
|
5
|
+
License-Expression: Apache-2.0
|
|
6
|
+
License-File: LICENSE.txt
|
|
7
|
+
Requires-Python: >=3.10,<3.12
|
|
8
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
9
|
+
Classifier: Operating System :: Unix
|
|
10
|
+
Classifier: Programming Language :: Python
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Requires-Dist: click (>=8.1.8,<9.0.0)
|
|
15
|
+
Requires-Dist: loguru (>=0.7.3,<0.8.0)
|
|
16
|
+
Requires-Dist: numpy
|
|
17
|
+
Requires-Dist: pandas
|
|
18
|
+
Requires-Dist: pydantic (==2.13.1)
|
|
19
|
+
Requires-Dist: pyspark (==3.5.1)
|
|
20
|
+
Requires-Dist: pyyaml (>=6.0,<7.0)
|
|
21
|
+
Requires-Dist: requests (==2.33.1)
|
|
22
|
+
Requires-Dist: salesforce-cdp-connector (>=1.0.19)
|
|
23
|
+
Requires-Dist: setuptools_scm (>=7.1.0,<8.0.0)
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# Data Cloud Custom Code SDK
|
|
2
27
|
|
|
3
28
|
This package provides a development kit for creating custom data transformations in [Data Cloud](https://www.salesforce.com/data/). It allows you to write your own data processing logic in Python while leveraging Data Cloud's infrastructure for data access and running data transformations, mapping execution into Data Cloud data structures like [Data Model Objects](https://help.salesforce.com/s/articleView?id=data.c360_a_data_model_objects.htm&type=5) and [Data Lake Objects](https://help.salesforce.com/s/articleView?id=sf.c360_a_data_lake_objects.htm&language=en_US&type=5).
|
|
4
29
|
|
|
@@ -11,7 +36,7 @@ Use of this project with Salesforce is subject to the [TERMS OF USE](./TERMS_OF_
|
|
|
11
36
|
- **Python 3.11 only** (currently supported version - if your system version is different, we recommend using [pyenv](https://github.com/pyenv/pyenv) to configure 3.11)
|
|
12
37
|
- JDK 17
|
|
13
38
|
- Docker support like [Docker Desktop](https://docs.docker.com/desktop/)
|
|
14
|
-
- A salesforce org with some DLOs or DMOs with data and this feature enabled
|
|
39
|
+
- A salesforce org with some DLOs or DMOs with data and this feature enabled
|
|
15
40
|
- **One of the following** for authentication:
|
|
16
41
|
- A Salesforce org already authenticated via the [Salesforce CLI](https://developer.salesforce.com/tools/salesforcecli)
|
|
17
42
|
(simplest — no External Client App needed)
|
|
@@ -91,7 +116,7 @@ After modifying the `entrypoint.py` as needed, using any dependencies you add in
|
|
|
91
116
|
```zsh
|
|
92
117
|
cd my_package
|
|
93
118
|
datacustomcode scan ./payload/entrypoint.py
|
|
94
|
-
datacustomcode deploy --path ./payload --name my_custom_script --cpu-size CPU_L
|
|
119
|
+
datacustomcode deploy --path ./payload --name my_custom_script --cpu-size CPU_L --sf-cli-org myorg
|
|
95
120
|
```
|
|
96
121
|
|
|
97
122
|
> [!TIP]
|
|
@@ -320,6 +345,7 @@ Options:
|
|
|
320
345
|
- `--description TEXT`: Description of the transformation job (default: "")
|
|
321
346
|
- `--network TEXT`: docker network (default: "default")
|
|
322
347
|
- `--cpu-size TEXT`: CPU size for the deployment (default: `CPU_2XL`). Available options: CPU_L(Large), CPU_XL(Extra Large), CPU_2XL(2X Large), CPU_4XL(4X Large)
|
|
348
|
+
- `--sf-cli-org TEXT`: Salesforce CLI org alias or username (e.g. `myorg`). Fetches credentials via `sf org display` — no `datacustomcode configure` step needed. Takes precedence over `--profile` if both are supplied.
|
|
323
349
|
- `--function-invoke-opt TEXT`: Currently we support only `UnstructuredChunking` for functions.
|
|
324
350
|
|
|
325
351
|
|
|
@@ -372,6 +398,56 @@ datacustomcode run ./payload/entrypoint.py --sf-cli-org myorg
|
|
|
372
398
|
```
|
|
373
399
|
|
|
374
400
|
|
|
401
|
+
## Testing Einstein Predictions
|
|
402
|
+
|
|
403
|
+
You can use AI models configured in Einstein Studio to score your data while
|
|
404
|
+
transforming it. As with the LLM Gateway, there are two flavors: a one-shot
|
|
405
|
+
scalar call (`client.einstein_predict`) and a per-row column helper
|
|
406
|
+
(`einstein_predict_col`). Below is a sample code example:
|
|
407
|
+
|
|
408
|
+
```
|
|
409
|
+
from datacustomcode.client import Client, einstein_predict_col
|
|
410
|
+
from datacustomcode.einstein_predictions.types import PredictionType
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def main():
|
|
414
|
+
client = Client()
|
|
415
|
+
df = client.read_dlo("Input__dll")
|
|
416
|
+
# einstein_predict_col returns a struct
|
|
417
|
+
# {status, response, error_code, error_message} per row, so per-row
|
|
418
|
+
# failures don't abort the Spark job. `response` is the prediction
|
|
419
|
+
# payload as a JSON string. Pick the field you want with [].
|
|
420
|
+
df_scored = df.withColumn(
|
|
421
|
+
"prediction__c",
|
|
422
|
+
einstein_predict_col(
|
|
423
|
+
"my_regression_model", # An AI model in your org
|
|
424
|
+
PredictionType.REGRESSION,
|
|
425
|
+
{"square_feet": col("square_feet__c"), "beds": col("beds__c")},
|
|
426
|
+
)["response"],
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
dlo_name = "Output_dll"
|
|
430
|
+
client.write_to_dlo(dlo_name, df_scored, write_mode=WriteMode.APPEND)
|
|
431
|
+
|
|
432
|
+
# One-shot scalar prediction returns the response payload as a dict
|
|
433
|
+
prediction = client.einstein_predict(
|
|
434
|
+
"my_regression_model",
|
|
435
|
+
PredictionType.REGRESSION,
|
|
436
|
+
{"square_feet": 1800, "beds": 3},
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
if __name__ == "__main__":
|
|
440
|
+
main()
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
Testing this code locally uses the same External Client App setup described in
|
|
444
|
+
[Testing LLM Gateway](#testing-llm-gateway). Once your `myorg` alias is set up,
|
|
445
|
+
run:
|
|
446
|
+
```
|
|
447
|
+
datacustomcode run ./payload/entrypoint.py --sf-cli-org myorg
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
|
|
375
451
|
## Docker usage
|
|
376
452
|
|
|
377
453
|
The SDK provides Docker-based development options that allow you to test your code in an environment that closely resembles Data Cloud's execution environment.
|
|
@@ -483,7 +559,7 @@ sf --version
|
|
|
483
559
|
**Browser-based (recommended for developer orgs and sandboxes):**
|
|
484
560
|
```zsh
|
|
485
561
|
# Production / Developer Edition
|
|
486
|
-
sf org login web --alias myorg
|
|
562
|
+
sf org login web --alias myorg --instance-url <your-instance-url>
|
|
487
563
|
|
|
488
564
|
# Sandbox
|
|
489
565
|
sf org login web --alias mysandbox --instance-url https://test.salesforce.com
|
|
@@ -513,3 +589,4 @@ If you're using OAuth Tokens authentication, the initial configure will retrieve
|
|
|
513
589
|
|
|
514
590
|
- [Troubleshooting](./docs/troubleshooting.md)
|
|
515
591
|
- [For Contributors](./FOR_CONTRIBUTORS.md)
|
|
592
|
+
|
salesforce_data_customcode-6.0.5.dev1/PKG-INFO → salesforce_data_customcode-6.0.7.dev1/README.md
RENAMED
|
@@ -1,29 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Name: salesforce-data-customcode
|
|
3
|
-
Version: 6.0.5.dev1
|
|
4
|
-
Summary: Data Cloud Custom Code SDK
|
|
5
|
-
License-Expression: Apache-2.0
|
|
6
|
-
License-File: LICENSE.txt
|
|
7
|
-
Requires-Python: >=3.10,<3.12
|
|
8
|
-
Classifier: Development Status :: 4 - Beta
|
|
9
|
-
Classifier: Operating System :: Unix
|
|
10
|
-
Classifier: Programming Language :: Python
|
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
-
Requires-Dist: click (>=8.1.8,<9.0.0)
|
|
15
|
-
Requires-Dist: loguru (>=0.7.3,<0.8.0)
|
|
16
|
-
Requires-Dist: numpy
|
|
17
|
-
Requires-Dist: pandas
|
|
18
|
-
Requires-Dist: pydantic (==2.13.1)
|
|
19
|
-
Requires-Dist: pyspark (==3.5.1)
|
|
20
|
-
Requires-Dist: pyyaml (>=6.0,<7.0)
|
|
21
|
-
Requires-Dist: requests (==2.33.1)
|
|
22
|
-
Requires-Dist: salesforce-cdp-connector (>=1.0.19)
|
|
23
|
-
Requires-Dist: setuptools_scm (>=7.1.0,<8.0.0)
|
|
24
|
-
Description-Content-Type: text/markdown
|
|
25
|
-
|
|
26
|
-
# Data Cloud Custom Code SDK (BETA)
|
|
1
|
+
# Data Cloud Custom Code SDK
|
|
27
2
|
|
|
28
3
|
This package provides a development kit for creating custom data transformations in [Data Cloud](https://www.salesforce.com/data/). It allows you to write your own data processing logic in Python while leveraging Data Cloud's infrastructure for data access and running data transformations, mapping execution into Data Cloud data structures like [Data Model Objects](https://help.salesforce.com/s/articleView?id=data.c360_a_data_model_objects.htm&type=5) and [Data Lake Objects](https://help.salesforce.com/s/articleView?id=sf.c360_a_data_lake_objects.htm&language=en_US&type=5).
|
|
29
4
|
|
|
@@ -36,7 +11,7 @@ Use of this project with Salesforce is subject to the [TERMS OF USE](./TERMS_OF_
|
|
|
36
11
|
- **Python 3.11 only** (currently supported version - if your system version is different, we recommend using [pyenv](https://github.com/pyenv/pyenv) to configure 3.11)
|
|
37
12
|
- JDK 17
|
|
38
13
|
- Docker support like [Docker Desktop](https://docs.docker.com/desktop/)
|
|
39
|
-
- A salesforce org with some DLOs or DMOs with data and this feature enabled
|
|
14
|
+
- A salesforce org with some DLOs or DMOs with data and this feature enabled
|
|
40
15
|
- **One of the following** for authentication:
|
|
41
16
|
- A Salesforce org already authenticated via the [Salesforce CLI](https://developer.salesforce.com/tools/salesforcecli)
|
|
42
17
|
(simplest — no External Client App needed)
|
|
@@ -116,7 +91,7 @@ After modifying the `entrypoint.py` as needed, using any dependencies you add in
|
|
|
116
91
|
```zsh
|
|
117
92
|
cd my_package
|
|
118
93
|
datacustomcode scan ./payload/entrypoint.py
|
|
119
|
-
datacustomcode deploy --path ./payload --name my_custom_script --cpu-size CPU_L
|
|
94
|
+
datacustomcode deploy --path ./payload --name my_custom_script --cpu-size CPU_L --sf-cli-org myorg
|
|
120
95
|
```
|
|
121
96
|
|
|
122
97
|
> [!TIP]
|
|
@@ -345,6 +320,7 @@ Options:
|
|
|
345
320
|
- `--description TEXT`: Description of the transformation job (default: "")
|
|
346
321
|
- `--network TEXT`: docker network (default: "default")
|
|
347
322
|
- `--cpu-size TEXT`: CPU size for the deployment (default: `CPU_2XL`). Available options: CPU_L(Large), CPU_XL(Extra Large), CPU_2XL(2X Large), CPU_4XL(4X Large)
|
|
323
|
+
- `--sf-cli-org TEXT`: Salesforce CLI org alias or username (e.g. `myorg`). Fetches credentials via `sf org display` — no `datacustomcode configure` step needed. Takes precedence over `--profile` if both are supplied.
|
|
348
324
|
- `--function-invoke-opt TEXT`: Currently we support only `UnstructuredChunking` for functions.
|
|
349
325
|
|
|
350
326
|
|
|
@@ -397,6 +373,56 @@ datacustomcode run ./payload/entrypoint.py --sf-cli-org myorg
|
|
|
397
373
|
```
|
|
398
374
|
|
|
399
375
|
|
|
376
|
+
## Testing Einstein Predictions
|
|
377
|
+
|
|
378
|
+
You can use AI models configured in Einstein Studio to score your data while
|
|
379
|
+
transforming it. As with the LLM Gateway, there are two flavors: a one-shot
|
|
380
|
+
scalar call (`client.einstein_predict`) and a per-row column helper
|
|
381
|
+
(`einstein_predict_col`). Below is a sample code example:
|
|
382
|
+
|
|
383
|
+
```
|
|
384
|
+
from datacustomcode.client import Client, einstein_predict_col
|
|
385
|
+
from datacustomcode.einstein_predictions.types import PredictionType
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def main():
|
|
389
|
+
client = Client()
|
|
390
|
+
df = client.read_dlo("Input__dll")
|
|
391
|
+
# einstein_predict_col returns a struct
|
|
392
|
+
# {status, response, error_code, error_message} per row, so per-row
|
|
393
|
+
# failures don't abort the Spark job. `response` is the prediction
|
|
394
|
+
# payload as a JSON string. Pick the field you want with [].
|
|
395
|
+
df_scored = df.withColumn(
|
|
396
|
+
"prediction__c",
|
|
397
|
+
einstein_predict_col(
|
|
398
|
+
"my_regression_model", # An AI model in your org
|
|
399
|
+
PredictionType.REGRESSION,
|
|
400
|
+
{"square_feet": col("square_feet__c"), "beds": col("beds__c")},
|
|
401
|
+
)["response"],
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
dlo_name = "Output_dll"
|
|
405
|
+
client.write_to_dlo(dlo_name, df_scored, write_mode=WriteMode.APPEND)
|
|
406
|
+
|
|
407
|
+
# One-shot scalar prediction returns the response payload as a dict
|
|
408
|
+
prediction = client.einstein_predict(
|
|
409
|
+
"my_regression_model",
|
|
410
|
+
PredictionType.REGRESSION,
|
|
411
|
+
{"square_feet": 1800, "beds": 3},
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
if __name__ == "__main__":
|
|
415
|
+
main()
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
Testing this code locally uses the same External Client App setup described in
|
|
419
|
+
[Testing LLM Gateway](#testing-llm-gateway). Once your `myorg` alias is set up,
|
|
420
|
+
run:
|
|
421
|
+
```
|
|
422
|
+
datacustomcode run ./payload/entrypoint.py --sf-cli-org myorg
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
|
|
400
426
|
## Docker usage
|
|
401
427
|
|
|
402
428
|
The SDK provides Docker-based development options that allow you to test your code in an environment that closely resembles Data Cloud's execution environment.
|
|
@@ -508,7 +534,7 @@ sf --version
|
|
|
508
534
|
**Browser-based (recommended for developer orgs and sandboxes):**
|
|
509
535
|
```zsh
|
|
510
536
|
# Production / Developer Edition
|
|
511
|
-
sf org login web --alias myorg
|
|
537
|
+
sf org login web --alias myorg --instance-url <your-instance-url>
|
|
512
538
|
|
|
513
539
|
# Sandbox
|
|
514
540
|
sf org login web --alias mysandbox --instance-url https://test.salesforce.com
|
|
@@ -538,4 +564,3 @@ If you're using OAuth Tokens authentication, the initial configure will retrieve
|
|
|
538
564
|
|
|
539
565
|
- [Troubleshooting](./docs/troubleshooting.md)
|
|
540
566
|
- [For Contributors](./FOR_CONTRIBUTORS.md)
|
|
541
|
-
|
{salesforce_data_customcode-6.0.5.dev1 → salesforce_data_customcode-6.0.7.dev1}/pyproject.toml
RENAMED
|
@@ -5,7 +5,7 @@ requires = ["poetry-core>=2.0.0", "poetry-dynamic-versioning>=1.0.0,<2.0.0"]
|
|
|
5
5
|
[project]
|
|
6
6
|
authors = []
|
|
7
7
|
classifiers = [
|
|
8
|
-
"Development Status ::
|
|
8
|
+
"Development Status :: 5 - Production/Stable",
|
|
9
9
|
"Operating System :: Unix",
|
|
10
10
|
"Programming Language :: Python",
|
|
11
11
|
"Programming Language :: Python :: 3",
|
|
@@ -18,7 +18,7 @@ license = "Apache-2.0"
|
|
|
18
18
|
name = "salesforce-data-customcode"
|
|
19
19
|
readme = "README.md"
|
|
20
20
|
requires-python = ">=3.10,<3.12"
|
|
21
|
-
version = "6.0.
|
|
21
|
+
version = "6.0.7.dev1"
|
|
22
22
|
|
|
23
23
|
[tool.black]
|
|
24
24
|
exclude = '''
|
|
@@ -17,10 +17,13 @@ __all__ = [
|
|
|
17
17
|
"AuthType",
|
|
18
18
|
"Client",
|
|
19
19
|
"Credentials",
|
|
20
|
+
"DefaultSparkEinsteinPredictions",
|
|
20
21
|
"DefaultSparkLLMGateway",
|
|
21
22
|
"PrintDataCloudWriter",
|
|
22
23
|
"QueryAPIDataCloudReader",
|
|
24
|
+
"SparkEinsteinPredictions",
|
|
23
25
|
"SparkLLMGateway",
|
|
26
|
+
"einstein_predict_col",
|
|
24
27
|
"llm_gateway_generate_text_col",
|
|
25
28
|
]
|
|
26
29
|
|
|
@@ -59,4 +62,16 @@ def __getattr__(name: str):
|
|
|
59
62
|
from datacustomcode.client import llm_gateway_generate_text_col
|
|
60
63
|
|
|
61
64
|
return llm_gateway_generate_text_col
|
|
65
|
+
elif name == "SparkEinsteinPredictions":
|
|
66
|
+
from datacustomcode.einstein_predictions import SparkEinsteinPredictions
|
|
67
|
+
|
|
68
|
+
return SparkEinsteinPredictions
|
|
69
|
+
elif name == "DefaultSparkEinsteinPredictions":
|
|
70
|
+
from datacustomcode.einstein_predictions import DefaultSparkEinsteinPredictions
|
|
71
|
+
|
|
72
|
+
return DefaultSparkEinsteinPredictions
|
|
73
|
+
elif name == "einstein_predict_col":
|
|
74
|
+
from datacustomcode.client import einstein_predict_col
|
|
75
|
+
|
|
76
|
+
return einstein_predict_col
|
|
62
77
|
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
@@ -17,6 +17,7 @@ from __future__ import annotations
|
|
|
17
17
|
from enum import Enum
|
|
18
18
|
from typing import (
|
|
19
19
|
TYPE_CHECKING,
|
|
20
|
+
Any,
|
|
20
21
|
ClassVar,
|
|
21
22
|
Dict,
|
|
22
23
|
Optional,
|
|
@@ -24,6 +25,7 @@ from typing import (
|
|
|
24
25
|
)
|
|
25
26
|
|
|
26
27
|
from datacustomcode.config import config
|
|
28
|
+
from datacustomcode.einstein_predictions_config import spark_einstein_predictions_config
|
|
27
29
|
from datacustomcode.file.path.default import DefaultFindFilePath
|
|
28
30
|
from datacustomcode.io.reader.base import BaseDataCloudReader
|
|
29
31
|
from datacustomcode.llm_gateway_config import spark_llm_gateway_config
|
|
@@ -34,6 +36,8 @@ if TYPE_CHECKING:
|
|
|
34
36
|
|
|
35
37
|
from pyspark.sql import Column, DataFrame as PySparkDataFrame
|
|
36
38
|
|
|
39
|
+
from datacustomcode.einstein_predictions.spark_base import SparkEinsteinPredictions
|
|
40
|
+
from datacustomcode.einstein_predictions.types import PredictionType
|
|
37
41
|
from datacustomcode.io.reader.base import BaseDataCloudReader
|
|
38
42
|
from datacustomcode.io.writer.base import BaseDataCloudWriter, WriteMode
|
|
39
43
|
from datacustomcode.llm_gateway.spark_base import SparkLLMGateway
|
|
@@ -99,6 +103,70 @@ def llm_gateway_generate_text_col(
|
|
|
99
103
|
return gateway.llm_gateway_generate_text_col(template, values, model_id=model_id)
|
|
100
104
|
|
|
101
105
|
|
|
106
|
+
def _build_spark_einstein_predictions() -> "SparkEinsteinPredictions":
|
|
107
|
+
"""Instantiate the SDK-configured :class:`SparkEinsteinPredictions`.
|
|
108
|
+
|
|
109
|
+
Raises:
|
|
110
|
+
RuntimeError: If no ``spark_einstein_predictions_config`` has been loaded.
|
|
111
|
+
"""
|
|
112
|
+
cfg = spark_einstein_predictions_config.spark_einstein_predictions_config
|
|
113
|
+
if cfg is None:
|
|
114
|
+
raise RuntimeError(
|
|
115
|
+
"spark_einstein_predictions_config is not configured. Add a "
|
|
116
|
+
"'spark_einstein_predictions_config' section to config.yaml."
|
|
117
|
+
)
|
|
118
|
+
return cfg.to_object()
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def einstein_predict_col(
|
|
122
|
+
model_api_name: str,
|
|
123
|
+
prediction_type: "PredictionType",
|
|
124
|
+
features: Dict[str, "Column"],
|
|
125
|
+
settings: Optional[Dict[str, Any]] = None,
|
|
126
|
+
) -> "Column":
|
|
127
|
+
"""Build a Spark Column that runs an Einstein prediction per row.
|
|
128
|
+
|
|
129
|
+
The returned Column yields a struct ``{status, response, error_code,
|
|
130
|
+
error_message}`` for each row. Use ``[...]`` (or ``getField``) to pick the
|
|
131
|
+
field you want, e.g. ``einstein_predict_col(...)["response"]``. ``response``
|
|
132
|
+
holds the prediction response payload as a JSON string. Per-row failures
|
|
133
|
+
populate ``status`` / ``error_code`` / ``error_message`` so a single bad row
|
|
134
|
+
does not abort the whole Spark job.
|
|
135
|
+
|
|
136
|
+
Example:
|
|
137
|
+
|
|
138
|
+
>>> from datacustomcode.einstein_predictions.types import PredictionType
|
|
139
|
+
>>> result = einstein_predict_col(
|
|
140
|
+
... "my_regression_model",
|
|
141
|
+
... PredictionType.REGRESSION,
|
|
142
|
+
... {"square_feet": col("square_feet__c"), "beds": col("beds__c")},
|
|
143
|
+
... )
|
|
144
|
+
>>> df.withColumn("prediction__c", result["response"])
|
|
145
|
+
>>> # …or keep the struct around and inspect failures:
|
|
146
|
+
>>> df.withColumn("pred", result).select(
|
|
147
|
+
... "pred.status", "pred.response", "pred.error_message"
|
|
148
|
+
... )
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
model_api_name: API name of the Einstein model to invoke.
|
|
152
|
+
prediction_type: The :class:`PredictionType` of the model.
|
|
153
|
+
features: A mapping from model feature column name to a Spark ``Column``
|
|
154
|
+
supplying that feature's per-row value.
|
|
155
|
+
settings: Optional prediction settings forwarded to the model.
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
A Spark ``Column`` of ``StructType`` with fields ``status``,
|
|
159
|
+
``response``, ``error_code``, and ``error_message`` (all nullable
|
|
160
|
+
strings). On success, ``status == "SUCCESS"`` and ``response`` holds
|
|
161
|
+
the JSON-serialized prediction payload; on failure, ``status ==
|
|
162
|
+
"ERROR"`` and the ``error_*`` fields carry diagnostic detail.
|
|
163
|
+
"""
|
|
164
|
+
predictions = Client()._get_spark_einstein_predictions()
|
|
165
|
+
return predictions.einstein_predict_col(
|
|
166
|
+
model_api_name, prediction_type, features, settings=settings
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
|
|
102
170
|
class DataCloudObjectType(Enum):
|
|
103
171
|
DLO = "dlo"
|
|
104
172
|
DMO = "dmo"
|
|
@@ -158,6 +226,8 @@ class Client:
|
|
|
158
226
|
reader: A custom reader to use for reading Data Cloud objects.
|
|
159
227
|
writer: A custom writer to use for writing Data Cloud objects.
|
|
160
228
|
spark_llm_gateway: Optional custom :class:`SparkLLMGateway`.
|
|
229
|
+
spark_einstein_predictions: Optional custom
|
|
230
|
+
:class:`SparkEinsteinPredictions`.
|
|
161
231
|
|
|
162
232
|
Example:
|
|
163
233
|
>>> client = Client()
|
|
@@ -172,6 +242,7 @@ class Client:
|
|
|
172
242
|
_writer: BaseDataCloudWriter
|
|
173
243
|
_file: DefaultFindFilePath
|
|
174
244
|
_spark_llm_gateway: Optional[SparkLLMGateway]
|
|
245
|
+
_spark_einstein_predictions: Optional[SparkEinsteinPredictions]
|
|
175
246
|
_data_layer_history: dict[DataCloudObjectType, set[str]]
|
|
176
247
|
_code_type: str
|
|
177
248
|
|
|
@@ -181,12 +252,14 @@ class Client:
|
|
|
181
252
|
writer: Optional[BaseDataCloudWriter] = None,
|
|
182
253
|
spark_provider: Optional[BaseSparkSessionProvider] = None,
|
|
183
254
|
spark_llm_gateway: Optional[SparkLLMGateway] = None,
|
|
255
|
+
spark_einstein_predictions: Optional[SparkEinsteinPredictions] = None,
|
|
184
256
|
code_type: str = "script",
|
|
185
257
|
) -> Client:
|
|
186
258
|
|
|
187
259
|
if cls._instance is None:
|
|
188
260
|
cls._instance = super().__new__(cls)
|
|
189
261
|
cls._instance._spark_llm_gateway = spark_llm_gateway
|
|
262
|
+
cls._instance._spark_einstein_predictions = spark_einstein_predictions
|
|
190
263
|
# Initialize Readers and Writers from config
|
|
191
264
|
# and/or provided reader and writer
|
|
192
265
|
if reader is None or writer is None:
|
|
@@ -358,6 +431,49 @@ class Client:
|
|
|
358
431
|
self._spark_llm_gateway = _build_spark_llm_gateway()
|
|
359
432
|
return self._spark_llm_gateway
|
|
360
433
|
|
|
434
|
+
def einstein_predict(
|
|
435
|
+
self,
|
|
436
|
+
model_api_name: str,
|
|
437
|
+
prediction_type: "PredictionType",
|
|
438
|
+
features: Dict[str, Any],
|
|
439
|
+
settings: Optional[Dict[str, Any]] = None,
|
|
440
|
+
) -> Dict[str, Any]:
|
|
441
|
+
"""Issue a one-shot Einstein prediction. This is the scalar counterpart
|
|
442
|
+
to :func:`einstein_predict_col`: it runs **once** — not per row. Use the
|
|
443
|
+
column helper method instead when you want to fan a prediction out
|
|
444
|
+
across every row of a DataFrame.
|
|
445
|
+
|
|
446
|
+
Example:
|
|
447
|
+
|
|
448
|
+
>>> from datacustomcode.einstein_predictions.types import PredictionType
|
|
449
|
+
>>> response = Client().einstein_predict(
|
|
450
|
+
... "my_regression_model",
|
|
451
|
+
... PredictionType.REGRESSION,
|
|
452
|
+
... {"square_feet": 1800, "beds": 3},
|
|
453
|
+
... )
|
|
454
|
+
|
|
455
|
+
Args:
|
|
456
|
+
model_api_name: API name of the Einstein model to invoke.
|
|
457
|
+
prediction_type: The :class:`PredictionType` of the model.
|
|
458
|
+
features: A mapping from model feature column name to a single
|
|
459
|
+
scalar value (``str`` / ``float`` / ``bool``).
|
|
460
|
+
settings: Optional prediction settings forwarded to the model.
|
|
461
|
+
|
|
462
|
+
Returns:
|
|
463
|
+
The prediction response payload as a plain Python ``dict``.
|
|
464
|
+
|
|
465
|
+
Raises:
|
|
466
|
+
EinsteinPredictionsCallError: If the prediction call fails.
|
|
467
|
+
"""
|
|
468
|
+
return self._get_spark_einstein_predictions().einstein_predict(
|
|
469
|
+
model_api_name, prediction_type, features, settings=settings
|
|
470
|
+
)
|
|
471
|
+
|
|
472
|
+
def _get_spark_einstein_predictions(self) -> SparkEinsteinPredictions:
|
|
473
|
+
if self._spark_einstein_predictions is None:
|
|
474
|
+
self._spark_einstein_predictions = _build_spark_einstein_predictions()
|
|
475
|
+
return self._spark_einstein_predictions
|
|
476
|
+
|
|
361
477
|
def _validate_data_layer_history_does_not_contain(
|
|
362
478
|
self, data_cloud_object_type: DataCloudObjectType
|
|
363
479
|
) -> None:
|
|
@@ -14,9 +14,17 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
|
|
16
16
|
from datacustomcode.einstein_predictions.base import EinsteinPredictions
|
|
17
|
+
from datacustomcode.einstein_predictions.errors import EinsteinPredictionsCallError
|
|
17
18
|
from datacustomcode.einstein_predictions.impl.default import DefaultEinsteinPredictions
|
|
19
|
+
from datacustomcode.einstein_predictions.spark_base import SparkEinsteinPredictions
|
|
20
|
+
from datacustomcode.einstein_predictions.spark_default import (
|
|
21
|
+
DefaultSparkEinsteinPredictions,
|
|
22
|
+
)
|
|
18
23
|
|
|
19
24
|
__all__ = [
|
|
20
25
|
"DefaultEinsteinPredictions",
|
|
26
|
+
"DefaultSparkEinsteinPredictions",
|
|
21
27
|
"EinsteinPredictions",
|
|
28
|
+
"EinsteinPredictionsCallError",
|
|
29
|
+
"SparkEinsteinPredictions",
|
|
22
30
|
]
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Copyright (c) 2025, Salesforce, Inc.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
"""Exceptions raised by Einstein Predictions implementations."""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from typing import Optional
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class EinsteinPredictionsCallError(RuntimeError):
|
|
23
|
+
"""Raised when an Einstein Predictions call returns an error."""
|
|
24
|
+
|
|
25
|
+
def __init__(
|
|
26
|
+
self,
|
|
27
|
+
message: str,
|
|
28
|
+
*,
|
|
29
|
+
status: Optional[object] = None,
|
|
30
|
+
error_code: Optional[str] = None,
|
|
31
|
+
error_message: Optional[str] = None,
|
|
32
|
+
) -> None:
|
|
33
|
+
super().__init__(message)
|
|
34
|
+
self.status = status
|
|
35
|
+
self.error_code = error_code
|
|
36
|
+
self.error_message = error_message
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Copyright (c) 2025, Salesforce, Inc.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from abc import ABC, abstractmethod
|
|
18
|
+
from typing import (
|
|
19
|
+
TYPE_CHECKING,
|
|
20
|
+
Any,
|
|
21
|
+
Dict,
|
|
22
|
+
Optional,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
from datacustomcode.mixin import UserExtendableNamedConfigMixin
|
|
26
|
+
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from pyspark.sql import Column
|
|
29
|
+
|
|
30
|
+
from datacustomcode.einstein_predictions.types import PredictionType
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class SparkEinsteinPredictions(ABC, UserExtendableNamedConfigMixin):
|
|
34
|
+
CONFIG_NAME: str
|
|
35
|
+
|
|
36
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
@abstractmethod
|
|
40
|
+
def einstein_predict(
|
|
41
|
+
self,
|
|
42
|
+
model_api_name: str,
|
|
43
|
+
prediction_type: PredictionType,
|
|
44
|
+
features: Dict[str, Any],
|
|
45
|
+
settings: Optional[Dict[str, Any]] = None,
|
|
46
|
+
) -> Dict[str, Any]:
|
|
47
|
+
"""Issue a one-shot Einstein prediction and return the response data.
|
|
48
|
+
|
|
49
|
+
``features`` maps each model feature column name to a single scalar
|
|
50
|
+
value (``str``/``float``/``bool``). The value is wrapped into a
|
|
51
|
+
single-element prediction column of the appropriate type.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
@abstractmethod
|
|
55
|
+
def einstein_predict_col(
|
|
56
|
+
self,
|
|
57
|
+
model_api_name: str,
|
|
58
|
+
prediction_type: PredictionType,
|
|
59
|
+
features: Dict[str, "Column"],
|
|
60
|
+
settings: Optional[Dict[str, Any]] = None,
|
|
61
|
+
) -> "Column":
|
|
62
|
+
"""Build a Spark ``Column`` that invokes Einstein predict per row and
|
|
63
|
+
yields a struct ``{status, response, error_code, error_message}``.
|
|
64
|
+
|
|
65
|
+
``features`` maps each model feature column name to a Spark ``Column``
|
|
66
|
+
supplying that feature's per-row value. Select an individual field,
|
|
67
|
+
e.g. ``einstein_predict_col(...)["response"]``. ``response`` holds the
|
|
68
|
+
prediction response payload as a JSON string. Returning a struct means
|
|
69
|
+
a single failing row leaves the rest of the DataFrame intact — callers
|
|
70
|
+
can inspect ``status`` / ``error_code`` per row instead of having the
|
|
71
|
+
Spark job abort.
|
|
72
|
+
"""
|