salesforce-data-customcode 6.0.3.dev1__tar.gz → 6.0.3.dev2__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.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/PKG-INFO +5 -2
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/README.md +4 -1
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/pyproject.toml +1 -1
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/client.py +20 -8
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/llm_gateway/spark_base.py +10 -1
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/llm_gateway/spark_default.py +70 -11
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/script/payload/entrypoint.py +4 -2
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/LICENSE.txt +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/__init__.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/auth.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/cli.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/cmd.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/common_config.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/config.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/config.yaml +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/constants.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/credentials.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/deploy.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/einstein_platform_client.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/einstein_platform_config.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/einstein_predictions/__init__.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/einstein_predictions/base.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/einstein_predictions/impl/default.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/einstein_predictions/types.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/einstein_predictions_config.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/file/__init__.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/file/base.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/file/path/__init__.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/file/path/default.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/function/__init__.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/function/base.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/function/feature_types/__init__.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/function/feature_types/chunking.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/function/runtime.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/function_utils.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/io/__init__.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/io/base.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/io/reader/__init__.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/io/reader/base.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/io/reader/query_api.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/io/reader/sf_cli.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/io/reader/utils.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/io/writer/__init__.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/io/writer/base.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/io/writer/csv.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/io/writer/print.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/llm_gateway/__init__.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/llm_gateway/base.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/llm_gateway/default.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/llm_gateway/errors.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/llm_gateway/types/__init__.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/llm_gateway/types/generate_text_request.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/llm_gateway/types/generate_text_request_builder.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/llm_gateway/types/generate_text_response.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/llm_gateway/types/generate_text_response_builder.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/llm_gateway_config.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/mixin.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/py.typed +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/run.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/scan.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/spark/__init__.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/spark/base.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/spark/default.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/template.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/__init__.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/function/.devcontainer/devcontainer.json +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/function/Dockerfile.dependencies +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/function/README.md +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/function/build_native_dependencies.sh +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/function/chunking/payload/config.json +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/function/chunking/payload/entrypoint.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/function/chunking/requirements.txt +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/function/example/chunking_with_llm/config.json +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/function/example/chunking_with_llm/entrypoint.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/function/example/chunking_with_llm/files/chunking_prompt.txt +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/function/example/chunking_with_llm/tests/test.json +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/function/example/chunking_with_prediction/config.json +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/function/example/chunking_with_prediction/entrypoint.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/function/example/chunking_with_prediction/tests/test.json +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/function/payload/config.json +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/function/payload/entrypoint.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/function/requirements-dev.txt +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/function/requirements.txt +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/script/.devcontainer/devcontainer.json +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/script/Dockerfile +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/script/Dockerfile.dependencies +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/script/README.md +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/script/account.ipynb +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/script/build_native_dependencies.sh +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/script/examples/employee_hierarchy/employee_data.csv +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/script/examples/employee_hierarchy/entrypoint.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/script/jupyterlab.sh +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/script/payload/config.json +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/script/requirements-dev.txt +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/templates/script/requirements.txt +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/token_provider.py +0 -0
- {salesforce_data_customcode-6.0.3.dev1 → salesforce_data_customcode-6.0.3.dev2}/src/datacustomcode/version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: salesforce-data-customcode
|
|
3
|
-
Version: 6.0.3.
|
|
3
|
+
Version: 6.0.3.dev2
|
|
4
4
|
Summary: Data Cloud Custom Code SDK
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
License-File: LICENSE.txt
|
|
@@ -341,13 +341,16 @@ from datacustomcode.client import Client, llm_gateway_generate_text_col
|
|
|
341
341
|
def main():
|
|
342
342
|
client = Client()
|
|
343
343
|
df = client.read_dlo("Input__dll")
|
|
344
|
+
# llm_gateway_generate_text_col returns a struct
|
|
345
|
+
# {status, response, error_code, error_message} per row, so per-row
|
|
346
|
+
# failures don't abort the Spark job. Pick the field you want with [].
|
|
344
347
|
df_generated = df.withColumn(
|
|
345
348
|
"greeting__c",
|
|
346
349
|
llm_gateway_generate_text_col(
|
|
347
350
|
"In one sentence, greet {name} from {city}.",
|
|
348
351
|
{"name": col("name__c"), "city": col("homecity__c")},
|
|
349
352
|
model_id="sfdc_ai__DefaultGPT4Omni", # An AI model in your org
|
|
350
|
-
),
|
|
353
|
+
)["response"],
|
|
351
354
|
)
|
|
352
355
|
|
|
353
356
|
dlo_name = "Output_dll"
|
|
@@ -316,13 +316,16 @@ from datacustomcode.client import Client, llm_gateway_generate_text_col
|
|
|
316
316
|
def main():
|
|
317
317
|
client = Client()
|
|
318
318
|
df = client.read_dlo("Input__dll")
|
|
319
|
+
# llm_gateway_generate_text_col returns a struct
|
|
320
|
+
# {status, response, error_code, error_message} per row, so per-row
|
|
321
|
+
# failures don't abort the Spark job. Pick the field you want with [].
|
|
319
322
|
df_generated = df.withColumn(
|
|
320
323
|
"greeting__c",
|
|
321
324
|
llm_gateway_generate_text_col(
|
|
322
325
|
"In one sentence, greet {name} from {city}.",
|
|
323
326
|
{"name": col("name__c"), "city": col("homecity__c")},
|
|
324
327
|
model_id="sfdc_ai__DefaultGPT4Omni", # An AI model in your org
|
|
325
|
-
),
|
|
328
|
+
)["response"],
|
|
326
329
|
)
|
|
327
330
|
|
|
328
331
|
dlo_name = "Output_dll"
|
|
@@ -62,15 +62,23 @@ def llm_gateway_generate_text_col(
|
|
|
62
62
|
) -> "Column":
|
|
63
63
|
"""Build a Spark Column that runs the LLM Gateway per row.
|
|
64
64
|
|
|
65
|
+
The returned Column yields a struct ``{status, response, error_code,
|
|
66
|
+
error_message}`` for each row. Use ``[...]`` (or ``getField``) to pick the
|
|
67
|
+
field you want, e.g. ``llm_gateway_generate_text_col(...)["response"]``.
|
|
68
|
+
Per-row failures populate ``status`` / ``error_code`` / ``error_message``
|
|
69
|
+
so a single bad row does not abort the whole Spark job.
|
|
70
|
+
|
|
65
71
|
Example:
|
|
66
72
|
|
|
67
|
-
>>>
|
|
68
|
-
... "
|
|
69
|
-
...
|
|
70
|
-
...
|
|
71
|
-
...
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
>>> result = llm_gateway_generate_text_col(
|
|
74
|
+
... "In one sentence, greet {name} from {city}.",
|
|
75
|
+
... {"name": col("name__c"), "city": col("homecity__c")},
|
|
76
|
+
... model_id="sfdc_ai__DefaultGPT4Omni",
|
|
77
|
+
... )
|
|
78
|
+
>>> df.withColumn("greeting__c", result["response"])
|
|
79
|
+
>>> # …or keep the struct around and inspect failures:
|
|
80
|
+
>>> df.withColumn("llm", result).select(
|
|
81
|
+
... "llm.status", "llm.response", "llm.error_message"
|
|
74
82
|
... )
|
|
75
83
|
|
|
76
84
|
Args:
|
|
@@ -81,7 +89,11 @@ def llm_gateway_generate_text_col(
|
|
|
81
89
|
model_id: LLM model id. Defaults to ``sfdc_ai__DefaultGPT4Omni``.
|
|
82
90
|
|
|
83
91
|
Returns:
|
|
84
|
-
A Spark ``Column``
|
|
92
|
+
A Spark ``Column`` of ``StructType`` with fields ``status``,
|
|
93
|
+
``response``, ``error_code``, and ``error_message`` (all nullable
|
|
94
|
+
strings). On success, ``status == "SUCCESS"`` and ``response`` holds
|
|
95
|
+
the generated text; on failure, ``status == "ERROR"`` and the
|
|
96
|
+
``error_*`` fields carry diagnostic detail.
|
|
85
97
|
"""
|
|
86
98
|
gateway = Client()._get_spark_llm_gateway()
|
|
87
99
|
return gateway.llm_gateway_generate_text_col(template, values, model_id=model_id)
|
|
@@ -50,4 +50,13 @@ class SparkLLMGateway(ABC, UserExtendableNamedConfigMixin):
|
|
|
50
50
|
values: Union[Dict[str, "Column"], "Column"],
|
|
51
51
|
model_id: Optional[str] = None,
|
|
52
52
|
) -> "Column":
|
|
53
|
-
"""Build a Spark ``Column`` that invokes the LLM Gateway per row
|
|
53
|
+
"""Build a Spark ``Column`` that invokes the LLM Gateway per row and
|
|
54
|
+
yields a struct ``{status, response, error_code, error_message}``.
|
|
55
|
+
|
|
56
|
+
Select an individual field, e.g.
|
|
57
|
+
``llm_gateway_generate_text_col(...)["response"]``. Returning a struct
|
|
58
|
+
means a single failing row doesn't abort the Spark job.
|
|
59
|
+
Failing row leaves the rest of the DataFrame intact — callers can
|
|
60
|
+
inspect ``status`` / ``error_code`` per row instead of having the
|
|
61
|
+
Spark job abort.
|
|
62
|
+
"""
|
|
@@ -28,10 +28,16 @@ if TYPE_CHECKING:
|
|
|
28
28
|
from pyspark.sql import Column
|
|
29
29
|
|
|
30
30
|
from datacustomcode.llm_gateway.base import LLMGateway
|
|
31
|
+
from datacustomcode.llm_gateway.types.generate_text_response import (
|
|
32
|
+
GenerateTextResponse,
|
|
33
|
+
)
|
|
31
34
|
|
|
32
35
|
|
|
33
36
|
_DEFAULT_LLM_MODEL_ID = "sfdc_ai__DefaultGPT4Omni"
|
|
34
37
|
|
|
38
|
+
_STATUS_SUCCESS = "SUCCESS"
|
|
39
|
+
_STATUS_ERROR = "ERROR"
|
|
40
|
+
|
|
35
41
|
|
|
36
42
|
class DefaultSparkLLMGateway(SparkLLMGateway):
|
|
37
43
|
|
|
@@ -60,9 +66,17 @@ class DefaultSparkLLMGateway(SparkLLMGateway):
|
|
|
60
66
|
values: Union[Dict[str, "Column"], "Column"],
|
|
61
67
|
model_id: Optional[str] = None,
|
|
62
68
|
) -> "Column":
|
|
63
|
-
|
|
69
|
+
"""Build a per-row UDF that returns a struct ``{status, response,
|
|
70
|
+
error_code, error_message}`` so per-row failures do not abort the
|
|
71
|
+
Spark job. Callers select the field they want, e.g.
|
|
72
|
+
``llm_gateway_generate_text_col(...)["response"]``.
|
|
73
|
+
"""
|
|
64
74
|
from pyspark.sql.functions import struct, udf
|
|
65
|
-
from pyspark.sql.types import
|
|
75
|
+
from pyspark.sql.types import (
|
|
76
|
+
StringType,
|
|
77
|
+
StructField,
|
|
78
|
+
StructType,
|
|
79
|
+
)
|
|
66
80
|
|
|
67
81
|
if isinstance(values, dict):
|
|
68
82
|
values_col = struct(*[v.alias(k) for k, v in values.items()])
|
|
@@ -70,19 +84,32 @@ class DefaultSparkLLMGateway(SparkLLMGateway):
|
|
|
70
84
|
values_col = values
|
|
71
85
|
|
|
72
86
|
gateway = self._llm_gateway
|
|
87
|
+
result_schema = StructType(
|
|
88
|
+
[
|
|
89
|
+
StructField("status", StringType(), True),
|
|
90
|
+
StructField("response", StringType(), True),
|
|
91
|
+
StructField("error_code", StringType(), True),
|
|
92
|
+
StructField("error_message", StringType(), True),
|
|
93
|
+
]
|
|
94
|
+
)
|
|
73
95
|
|
|
74
|
-
def _generate(values_row: Any) -> str:
|
|
96
|
+
def _generate(values_row: Any) -> Dict[str, Optional[str]]:
|
|
75
97
|
if values_row is None:
|
|
76
|
-
return
|
|
98
|
+
return {
|
|
99
|
+
"status": _STATUS_ERROR,
|
|
100
|
+
"response": None,
|
|
101
|
+
"error_code": None,
|
|
102
|
+
"error_message": "values column was null for this row",
|
|
103
|
+
}
|
|
77
104
|
subs = (
|
|
78
105
|
values_row.asDict()
|
|
79
106
|
if hasattr(values_row, "asDict")
|
|
80
107
|
else dict(values_row)
|
|
81
108
|
)
|
|
82
109
|
prompt = template.format(**subs)
|
|
83
|
-
return
|
|
110
|
+
return _invoke_llm_gateway_as_struct(gateway, prompt, model_id)
|
|
84
111
|
|
|
85
|
-
return udf(_generate,
|
|
112
|
+
return udf(_generate, result_schema)(values_col)
|
|
86
113
|
|
|
87
114
|
|
|
88
115
|
def _build_underlying_gateway() -> "LLMGateway":
|
|
@@ -97,22 +124,33 @@ def _build_underlying_gateway() -> "LLMGateway":
|
|
|
97
124
|
return cfg.to_object()
|
|
98
125
|
|
|
99
126
|
|
|
100
|
-
def
|
|
127
|
+
def _call_llm_gateway(
|
|
101
128
|
gateway: "LLMGateway",
|
|
102
129
|
prompt: str,
|
|
103
130
|
model_id: Optional[str],
|
|
104
|
-
) ->
|
|
105
|
-
|
|
131
|
+
) -> "GenerateTextResponse":
|
|
132
|
+
"""Build the request and dispatch it to the underlying gateway."""
|
|
106
133
|
from datacustomcode.llm_gateway.types.generate_text_request_builder import (
|
|
107
134
|
GenerateTextRequestBuilder,
|
|
108
135
|
)
|
|
109
136
|
|
|
110
|
-
|
|
137
|
+
request = (
|
|
111
138
|
GenerateTextRequestBuilder()
|
|
112
139
|
.set_prompt(prompt)
|
|
113
140
|
.set_model(model_id or _DEFAULT_LLM_MODEL_ID)
|
|
141
|
+
.build()
|
|
114
142
|
)
|
|
115
|
-
|
|
143
|
+
return gateway.generate_text(request)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _invoke_llm_gateway(
|
|
147
|
+
gateway: "LLMGateway",
|
|
148
|
+
prompt: str,
|
|
149
|
+
model_id: Optional[str],
|
|
150
|
+
) -> str:
|
|
151
|
+
from datacustomcode.llm_gateway.errors import LLMGatewayCallError
|
|
152
|
+
|
|
153
|
+
response = _call_llm_gateway(gateway, prompt, model_id)
|
|
116
154
|
if response.is_error:
|
|
117
155
|
raise LLMGatewayCallError(
|
|
118
156
|
f"LLM Gateway call failed: status_code={response.status_code}, "
|
|
@@ -123,3 +161,24 @@ def _invoke_llm_gateway(
|
|
|
123
161
|
error_message=str(response.data) if response.data else None,
|
|
124
162
|
)
|
|
125
163
|
return response.text
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _invoke_llm_gateway_as_struct(
|
|
167
|
+
gateway: "LLMGateway",
|
|
168
|
+
prompt: str,
|
|
169
|
+
model_id: Optional[str],
|
|
170
|
+
) -> Dict[str, Optional[str]]:
|
|
171
|
+
response = _call_llm_gateway(gateway, prompt, model_id)
|
|
172
|
+
if response.is_error:
|
|
173
|
+
return {
|
|
174
|
+
"status": _STATUS_ERROR,
|
|
175
|
+
"response": None,
|
|
176
|
+
"error_code": response.error_code or None,
|
|
177
|
+
"error_message": str(response.data) if response.data else None,
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
"status": _STATUS_SUCCESS,
|
|
181
|
+
"response": response.text,
|
|
182
|
+
"error_code": None,
|
|
183
|
+
"error_message": None,
|
|
184
|
+
}
|
|
@@ -16,7 +16,9 @@ def main():
|
|
|
16
16
|
You can use your AI models configured in Salesforce to generate column
|
|
17
17
|
values. See README.md for how to test locally before deploying to Data Cloud.
|
|
18
18
|
|
|
19
|
-
Example
|
|
19
|
+
Example (the per-row helper returns a struct
|
|
20
|
+
``{status, response, error_code, error_message}`` — pick the field you
|
|
21
|
+
want with ``[...]``):
|
|
20
22
|
|
|
21
23
|
>>> from datacustomcode.client import llm_gateway_generate_text_col
|
|
22
24
|
df_generated = df.withColumn(
|
|
@@ -25,7 +27,7 @@ def main():
|
|
|
25
27
|
... "In one sentence, greet {name} from {city}.",
|
|
26
28
|
... {"name": col("name__c"), "city": col("homecity__c")},
|
|
27
29
|
... model_id="sfdc_ai__DefaultGPT4Omni",
|
|
28
|
-
... ),
|
|
30
|
+
... )["response"],
|
|
29
31
|
... )
|
|
30
32
|
|
|
31
33
|
You can also invoke the LLM with a literal plain text prompt — no
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|