salesforce-data-customcode 6.0.1.dev1__py3-none-any.whl → 6.0.2.dev1__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.
- datacustomcode/__init__.py +15 -0
- datacustomcode/client.py +102 -1
- datacustomcode/config.yaml +3 -0
- datacustomcode/einstein_platform_config.py +8 -4
- datacustomcode/einstein_predictions_config.py +1 -1
- datacustomcode/function/feature_types/chunking.py +1 -0
- datacustomcode/llm_gateway/__init__.py +4 -0
- datacustomcode/llm_gateway/default.py +2 -0
- datacustomcode/llm_gateway/spark_base.py +55 -0
- datacustomcode/llm_gateway/spark_default.py +119 -0
- datacustomcode/llm_gateway/types/generate_text_request.py +7 -0
- datacustomcode/llm_gateway/types/generate_text_request_builder.py +6 -0
- datacustomcode/llm_gateway_config.py +43 -2
- datacustomcode/templates/function/example/chunking_with_llm/entrypoint.py +3 -0
- datacustomcode/templates/function/example/chunking_with_prediction/entrypoint.py +3 -0
- datacustomcode/templates/function/payload/entrypoint.py +11 -12
- datacustomcode/templates/script/payload/entrypoint.py +27 -0
- datacustomcode/token_provider.py +36 -63
- {salesforce_data_customcode-6.0.1.dev1.dist-info → salesforce_data_customcode-6.0.2.dev1.dist-info}/METADATA +48 -1
- {salesforce_data_customcode-6.0.1.dev1.dist-info → salesforce_data_customcode-6.0.2.dev1.dist-info}/RECORD +23 -25
- datacustomcode/proxy/__init__.py +0 -14
- datacustomcode/proxy/base.py +0 -24
- datacustomcode/proxy/client/__init__.py +0 -14
- datacustomcode/proxy/client/base.py +0 -32
- {salesforce_data_customcode-6.0.1.dev1.dist-info → salesforce_data_customcode-6.0.2.dev1.dist-info}/WHEEL +0 -0
- {salesforce_data_customcode-6.0.1.dev1.dist-info → salesforce_data_customcode-6.0.2.dev1.dist-info}/entry_points.txt +0 -0
- {salesforce_data_customcode-6.0.1.dev1.dist-info → salesforce_data_customcode-6.0.2.dev1.dist-info}/licenses/LICENSE.txt +0 -0
datacustomcode/__init__.py
CHANGED
|
@@ -17,8 +17,11 @@ __all__ = [
|
|
|
17
17
|
"AuthType",
|
|
18
18
|
"Client",
|
|
19
19
|
"Credentials",
|
|
20
|
+
"DefaultSparkLLMGateway",
|
|
20
21
|
"PrintDataCloudWriter",
|
|
21
22
|
"QueryAPIDataCloudReader",
|
|
23
|
+
"SparkLLMGateway",
|
|
24
|
+
"llm_gateway_generate_text_col",
|
|
22
25
|
]
|
|
23
26
|
|
|
24
27
|
|
|
@@ -44,4 +47,16 @@ def __getattr__(name: str):
|
|
|
44
47
|
from datacustomcode.io.reader.query_api import QueryAPIDataCloudReader
|
|
45
48
|
|
|
46
49
|
return QueryAPIDataCloudReader
|
|
50
|
+
elif name == "SparkLLMGateway":
|
|
51
|
+
from datacustomcode.llm_gateway import SparkLLMGateway
|
|
52
|
+
|
|
53
|
+
return SparkLLMGateway
|
|
54
|
+
elif name == "DefaultSparkLLMGateway":
|
|
55
|
+
from datacustomcode.llm_gateway import DefaultSparkLLMGateway
|
|
56
|
+
|
|
57
|
+
return DefaultSparkLLMGateway
|
|
58
|
+
elif name == "llm_gateway_generate_text_col":
|
|
59
|
+
from datacustomcode.client import llm_gateway_generate_text_col
|
|
60
|
+
|
|
61
|
+
return llm_gateway_generate_text_col
|
|
47
62
|
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
datacustomcode/client.py
CHANGED
|
@@ -18,24 +18,80 @@ from enum import Enum
|
|
|
18
18
|
from typing import (
|
|
19
19
|
TYPE_CHECKING,
|
|
20
20
|
ClassVar,
|
|
21
|
+
Dict,
|
|
21
22
|
Optional,
|
|
23
|
+
Union,
|
|
22
24
|
)
|
|
23
25
|
|
|
24
26
|
from datacustomcode.config import config
|
|
25
27
|
from datacustomcode.file.path.default import DefaultFindFilePath
|
|
26
28
|
from datacustomcode.io.reader.base import BaseDataCloudReader
|
|
29
|
+
from datacustomcode.llm_gateway_config import spark_llm_gateway_config
|
|
27
30
|
from datacustomcode.spark.default import DefaultSparkSessionProvider
|
|
28
31
|
|
|
29
32
|
if TYPE_CHECKING:
|
|
30
33
|
from pathlib import Path
|
|
31
34
|
|
|
32
|
-
from pyspark.sql import DataFrame as PySparkDataFrame
|
|
35
|
+
from pyspark.sql import Column, DataFrame as PySparkDataFrame
|
|
33
36
|
|
|
34
37
|
from datacustomcode.io.reader.base import BaseDataCloudReader
|
|
35
38
|
from datacustomcode.io.writer.base import BaseDataCloudWriter, WriteMode
|
|
39
|
+
from datacustomcode.llm_gateway.spark_base import SparkLLMGateway
|
|
36
40
|
from datacustomcode.spark.base import BaseSparkSessionProvider
|
|
37
41
|
|
|
38
42
|
|
|
43
|
+
def _build_spark_llm_gateway() -> "SparkLLMGateway":
|
|
44
|
+
"""Instantiate the SDK-configured :class:`SparkLLMGateway`.
|
|
45
|
+
|
|
46
|
+
Raises:
|
|
47
|
+
RuntimeError: If no ``spark_llm_gateway_config`` has been loaded.
|
|
48
|
+
"""
|
|
49
|
+
cfg = spark_llm_gateway_config.spark_llm_gateway_config
|
|
50
|
+
if cfg is None:
|
|
51
|
+
raise RuntimeError(
|
|
52
|
+
"spark_llm_gateway_config is not configured. Add a "
|
|
53
|
+
"'spark_llm_gateway_config' section to config.yaml."
|
|
54
|
+
)
|
|
55
|
+
return cfg.to_object()
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def llm_gateway_generate_text_col(
|
|
59
|
+
template: str,
|
|
60
|
+
values: Union[Dict[str, "Column"], "Column"],
|
|
61
|
+
model_id: Optional[str] = None,
|
|
62
|
+
max_tokens: Optional[int] = None,
|
|
63
|
+
) -> "Column":
|
|
64
|
+
"""Build a Spark Column that runs the LLM Gateway per row.
|
|
65
|
+
|
|
66
|
+
Example:
|
|
67
|
+
|
|
68
|
+
>>> df.withColumn(
|
|
69
|
+
... "greeting__c",
|
|
70
|
+
... llm_gateway_generate_text_col(
|
|
71
|
+
... "In one sentence, greet {name} from {city}.",
|
|
72
|
+
... {"name": col("name__c"), "city": col("homecity__c")},
|
|
73
|
+
... model_id="sfdc_ai__DefaultGPT4Omni",
|
|
74
|
+
... max_tokens=100,
|
|
75
|
+
... ),
|
|
76
|
+
... )
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
template: The prompt template, with ``{field}`` placeholders matching
|
|
80
|
+
keys in ``values``. Substitution uses ``str.format``.
|
|
81
|
+
values: Either a mapping from placeholder name to Spark ``Column``, or
|
|
82
|
+
a single ``Column`` whose value is already a struct.
|
|
83
|
+
model_id: LLM model id. Defaults to ``sfdc_ai__DefaultGPT4Omni``.
|
|
84
|
+
max_tokens: Maximum tokens to generate. Defaults to 200.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
A Spark ``Column`` that, when evaluated, produces the generated text.
|
|
88
|
+
"""
|
|
89
|
+
gateway = Client()._get_spark_llm_gateway()
|
|
90
|
+
return gateway.llm_gateway_generate_text_col(
|
|
91
|
+
template, values, model_id=model_id, max_tokens=max_tokens
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
39
95
|
class DataCloudObjectType(Enum):
|
|
40
96
|
DLO = "dlo"
|
|
41
97
|
DMO = "dmo"
|
|
@@ -94,18 +150,23 @@ class Client:
|
|
|
94
150
|
finder: Find a file path
|
|
95
151
|
reader: A custom reader to use for reading Data Cloud objects.
|
|
96
152
|
writer: A custom writer to use for writing Data Cloud objects.
|
|
153
|
+
spark_llm_gateway: Optional custom :class:`SparkLLMGateway`. When
|
|
154
|
+
omitted, the gateway is lazily resolved from
|
|
155
|
+
``spark_llm_gateway_config``.
|
|
97
156
|
|
|
98
157
|
Example:
|
|
99
158
|
>>> client = Client()
|
|
100
159
|
>>> file_path = client.find_file_path("data.csv")
|
|
101
160
|
>>> dlo = client.read_dlo("my_dlo")
|
|
102
161
|
>>> client.write_to_dmo("my_dmo", dlo)
|
|
162
|
+
>>> answer = client.llm_gateway_generate_text("Generate a greeting message")
|
|
103
163
|
"""
|
|
104
164
|
|
|
105
165
|
_instance: ClassVar[Optional[Client]] = None
|
|
106
166
|
_reader: BaseDataCloudReader
|
|
107
167
|
_writer: BaseDataCloudWriter
|
|
108
168
|
_file: DefaultFindFilePath
|
|
169
|
+
_spark_llm_gateway: Optional[SparkLLMGateway]
|
|
109
170
|
_data_layer_history: dict[DataCloudObjectType, set[str]]
|
|
110
171
|
_code_type: str
|
|
111
172
|
|
|
@@ -114,11 +175,13 @@ class Client:
|
|
|
114
175
|
reader: Optional[BaseDataCloudReader] = None,
|
|
115
176
|
writer: Optional[BaseDataCloudWriter] = None,
|
|
116
177
|
spark_provider: Optional[BaseSparkSessionProvider] = None,
|
|
178
|
+
spark_llm_gateway: Optional[SparkLLMGateway] = None,
|
|
117
179
|
code_type: str = "script",
|
|
118
180
|
) -> Client:
|
|
119
181
|
|
|
120
182
|
if cls._instance is None:
|
|
121
183
|
cls._instance = super().__new__(cls)
|
|
184
|
+
cls._instance._spark_llm_gateway = spark_llm_gateway
|
|
122
185
|
# Initialize Readers and Writers from config
|
|
123
186
|
# and/or provided reader and writer
|
|
124
187
|
if reader is None or writer is None:
|
|
@@ -225,6 +288,44 @@ class Client:
|
|
|
225
288
|
|
|
226
289
|
return self._file.find_file_path(file_name) # type: ignore[no-any-return]
|
|
227
290
|
|
|
291
|
+
def llm_gateway_generate_text(
|
|
292
|
+
self,
|
|
293
|
+
prompt: str,
|
|
294
|
+
model_id: Optional[str] = None,
|
|
295
|
+
max_tokens: Optional[int] = None,
|
|
296
|
+
) -> str:
|
|
297
|
+
"""Issue a one-shot LLM Gateway call. This is the scalar counterpart to
|
|
298
|
+
:func:`llm_gateway_generate_text_col`: it runs **once** — not per row.
|
|
299
|
+
Use the column helper method instead when you want to fan a prompt out across
|
|
300
|
+
every row of a DataFrame.
|
|
301
|
+
|
|
302
|
+
Example:
|
|
303
|
+
|
|
304
|
+
>>> response = Client().llm_gateway_generate_text(
|
|
305
|
+
... "Generate a greeting message"
|
|
306
|
+
... )
|
|
307
|
+
|
|
308
|
+
Args:
|
|
309
|
+
prompt: The literal prompt to send. Plain text — no
|
|
310
|
+
``{field}`` substitution is performed on this string.
|
|
311
|
+
model_id: LLM model id to target. Defaults to
|
|
312
|
+
``sfdc_ai__DefaultGPT4Omni`` when ``None``.
|
|
313
|
+
max_tokens: Hard upper bound on the number of tokens the model
|
|
314
|
+
may generate. Defaults to 200 when ``None``.
|
|
315
|
+
|
|
316
|
+
Returns:
|
|
317
|
+
The generated text as a plain Python ``str``; empty when the
|
|
318
|
+
gateway response carries no generated text.
|
|
319
|
+
"""
|
|
320
|
+
return self._get_spark_llm_gateway().llm_gateway_generate_text(
|
|
321
|
+
prompt, model_id=model_id, max_tokens=max_tokens
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
def _get_spark_llm_gateway(self) -> SparkLLMGateway:
|
|
325
|
+
if self._spark_llm_gateway is None:
|
|
326
|
+
self._spark_llm_gateway = _build_spark_llm_gateway()
|
|
327
|
+
return self._spark_llm_gateway
|
|
328
|
+
|
|
228
329
|
def _validate_data_layer_history_does_not_contain(
|
|
229
330
|
self, data_cloud_object_type: DataCloudObjectType
|
|
230
331
|
) -> None:
|
datacustomcode/config.yaml
CHANGED
|
@@ -15,20 +15,23 @@
|
|
|
15
15
|
|
|
16
16
|
from typing import (
|
|
17
17
|
ClassVar,
|
|
18
|
+
Generic,
|
|
18
19
|
Optional,
|
|
19
20
|
Type,
|
|
20
|
-
|
|
21
|
+
TypeVar,
|
|
21
22
|
)
|
|
22
23
|
|
|
23
24
|
from datacustomcode.common_config import BaseObjectConfig
|
|
24
25
|
|
|
26
|
+
_T = TypeVar("_T")
|
|
25
27
|
|
|
26
|
-
|
|
28
|
+
|
|
29
|
+
class CredentialsObjectConfig(BaseObjectConfig, Generic[_T]):
|
|
27
30
|
type_to_create: ClassVar[Type]
|
|
28
31
|
credentials_profile: Optional[str] = None
|
|
29
32
|
sf_cli_org: Optional[str] = None
|
|
30
33
|
|
|
31
|
-
def to_object(self):
|
|
34
|
+
def to_object(self) -> _T:
|
|
32
35
|
"""Create an object instance, automatically including credentials in options"""
|
|
33
36
|
|
|
34
37
|
options = self.options.copy()
|
|
@@ -38,4 +41,5 @@ class CredentialsObjectConfig(BaseObjectConfig):
|
|
|
38
41
|
options["sf_cli_org"] = self.sf_cli_org
|
|
39
42
|
|
|
40
43
|
type_ = self.type_to_create.subclass_from_config_name(self.type_config_name)
|
|
41
|
-
|
|
44
|
+
instance: _T = type_(**options)
|
|
45
|
+
return instance
|
|
@@ -28,7 +28,7 @@ from datacustomcode.einstein_predictions.base import EinsteinPredictions
|
|
|
28
28
|
_E = TypeVar("_E", bound=EinsteinPredictions)
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
class EinsteinPredictionsObjectConfig(CredentialsObjectConfig, Generic[_E]):
|
|
31
|
+
class EinsteinPredictionsObjectConfig(CredentialsObjectConfig[_E], Generic[_E]):
|
|
32
32
|
type_to_create: ClassVar[Type[EinsteinPredictions]] = EinsteinPredictions # type: ignore[type-abstract]
|
|
33
33
|
|
|
34
34
|
|
|
@@ -15,8 +15,12 @@
|
|
|
15
15
|
|
|
16
16
|
from datacustomcode.llm_gateway.base import LLMGateway
|
|
17
17
|
from datacustomcode.llm_gateway.default import DefaultLLMGateway
|
|
18
|
+
from datacustomcode.llm_gateway.spark_base import SparkLLMGateway
|
|
19
|
+
from datacustomcode.llm_gateway.spark_default import DefaultSparkLLMGateway
|
|
18
20
|
|
|
19
21
|
__all__ = [
|
|
20
22
|
"DefaultLLMGateway",
|
|
23
|
+
"DefaultSparkLLMGateway",
|
|
21
24
|
"LLMGateway",
|
|
25
|
+
"SparkLLMGateway",
|
|
22
26
|
]
|
|
@@ -34,6 +34,8 @@ class DefaultLLMGateway(EinsteinPlatformClient, LLMGateway):
|
|
|
34
34
|
|
|
35
35
|
payload: Dict[str, Any] = {"prompt": request.prompt}
|
|
36
36
|
|
|
37
|
+
if request.max_tokens is not None:
|
|
38
|
+
payload["max_tokens"] = request.max_tokens
|
|
37
39
|
if request.localization:
|
|
38
40
|
payload["localization"] = request.localization
|
|
39
41
|
if request.tags:
|
|
@@ -0,0 +1,55 @@
|
|
|
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
|
+
Union,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
from datacustomcode.mixin import UserExtendableNamedConfigMixin
|
|
27
|
+
|
|
28
|
+
if TYPE_CHECKING:
|
|
29
|
+
from pyspark.sql import Column
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class SparkLLMGateway(ABC, UserExtendableNamedConfigMixin):
|
|
33
|
+
CONFIG_NAME: str
|
|
34
|
+
|
|
35
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
@abstractmethod
|
|
39
|
+
def llm_gateway_generate_text(
|
|
40
|
+
self,
|
|
41
|
+
prompt: str,
|
|
42
|
+
model_id: Optional[str] = None,
|
|
43
|
+
max_tokens: Optional[int] = None,
|
|
44
|
+
) -> str:
|
|
45
|
+
"""Issue a one-shot LLM Gateway call and return the generated text."""
|
|
46
|
+
|
|
47
|
+
@abstractmethod
|
|
48
|
+
def llm_gateway_generate_text_col(
|
|
49
|
+
self,
|
|
50
|
+
template: str,
|
|
51
|
+
values: Union[Dict[str, "Column"], "Column"],
|
|
52
|
+
model_id: Optional[str] = None,
|
|
53
|
+
max_tokens: Optional[int] = None,
|
|
54
|
+
) -> "Column":
|
|
55
|
+
"""Build a Spark ``Column`` that invokes the LLM Gateway per row."""
|
|
@@ -0,0 +1,119 @@
|
|
|
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 typing import (
|
|
18
|
+
TYPE_CHECKING,
|
|
19
|
+
Any,
|
|
20
|
+
Dict,
|
|
21
|
+
Optional,
|
|
22
|
+
Union,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
from datacustomcode.llm_gateway.spark_base import SparkLLMGateway
|
|
26
|
+
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from pyspark.sql import Column
|
|
29
|
+
|
|
30
|
+
from datacustomcode.llm_gateway.base import LLMGateway
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
_DEFAULT_LLM_MODEL_ID = "sfdc_ai__DefaultGPT4Omni"
|
|
34
|
+
_DEFAULT_LLM_MAX_TOKENS = 200
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class DefaultSparkLLMGateway(SparkLLMGateway):
|
|
38
|
+
|
|
39
|
+
CONFIG_NAME = "DefaultSparkLLMGateway"
|
|
40
|
+
|
|
41
|
+
def __init__(
|
|
42
|
+
self,
|
|
43
|
+
llm_gateway: Optional["LLMGateway"] = None,
|
|
44
|
+
**kwargs: Any,
|
|
45
|
+
) -> None:
|
|
46
|
+
super().__init__(**kwargs)
|
|
47
|
+
if llm_gateway is None:
|
|
48
|
+
llm_gateway = _build_underlying_gateway()
|
|
49
|
+
self._llm_gateway: "LLMGateway" = llm_gateway
|
|
50
|
+
|
|
51
|
+
def llm_gateway_generate_text(
|
|
52
|
+
self,
|
|
53
|
+
prompt: str,
|
|
54
|
+
model_id: Optional[str] = None,
|
|
55
|
+
max_tokens: Optional[int] = None,
|
|
56
|
+
) -> str:
|
|
57
|
+
return _invoke_llm_gateway(self._llm_gateway, prompt, model_id, max_tokens)
|
|
58
|
+
|
|
59
|
+
def llm_gateway_generate_text_col(
|
|
60
|
+
self,
|
|
61
|
+
template: str,
|
|
62
|
+
values: Union[Dict[str, "Column"], "Column"],
|
|
63
|
+
model_id: Optional[str] = None,
|
|
64
|
+
max_tokens: Optional[int] = None,
|
|
65
|
+
) -> "Column":
|
|
66
|
+
|
|
67
|
+
from pyspark.sql.functions import struct, udf
|
|
68
|
+
from pyspark.sql.types import StringType
|
|
69
|
+
|
|
70
|
+
if isinstance(values, dict):
|
|
71
|
+
values_col = struct(*[v.alias(k) for k, v in values.items()])
|
|
72
|
+
else:
|
|
73
|
+
values_col = values
|
|
74
|
+
|
|
75
|
+
gateway = self._llm_gateway
|
|
76
|
+
|
|
77
|
+
def _generate(values_row: Any) -> str:
|
|
78
|
+
if values_row is None:
|
|
79
|
+
return ""
|
|
80
|
+
subs = (
|
|
81
|
+
values_row.asDict()
|
|
82
|
+
if hasattr(values_row, "asDict")
|
|
83
|
+
else dict(values_row)
|
|
84
|
+
)
|
|
85
|
+
prompt = template.format(**subs)
|
|
86
|
+
return _invoke_llm_gateway(gateway, prompt, model_id, max_tokens)
|
|
87
|
+
|
|
88
|
+
return udf(_generate, StringType())(values_col)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _build_underlying_gateway() -> "LLMGateway":
|
|
92
|
+
from datacustomcode.llm_gateway_config import llm_gateway_config
|
|
93
|
+
|
|
94
|
+
cfg = llm_gateway_config.llm_gateway_config
|
|
95
|
+
if cfg is None:
|
|
96
|
+
raise RuntimeError(
|
|
97
|
+
"llm_gateway_config is not configured. Add an 'llm_gateway_config' "
|
|
98
|
+
"section to config.yaml."
|
|
99
|
+
)
|
|
100
|
+
return cfg.to_object()
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _invoke_llm_gateway(
|
|
104
|
+
gateway: "LLMGateway",
|
|
105
|
+
prompt: str,
|
|
106
|
+
model_id: Optional[str],
|
|
107
|
+
max_tokens: Optional[int],
|
|
108
|
+
) -> str:
|
|
109
|
+
from datacustomcode.llm_gateway.types.generate_text_request_builder import (
|
|
110
|
+
GenerateTextRequestBuilder,
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
builder = (
|
|
114
|
+
GenerateTextRequestBuilder()
|
|
115
|
+
.set_prompt(prompt)
|
|
116
|
+
.set_model(model_id or _DEFAULT_LLM_MODEL_ID)
|
|
117
|
+
.set_max_tokens(max_tokens or _DEFAULT_LLM_MAX_TOKENS)
|
|
118
|
+
)
|
|
119
|
+
return gateway.generate_text(builder.build()).text
|
|
@@ -40,6 +40,13 @@ class GenerateTextRequest(BaseModel):
|
|
|
40
40
|
)
|
|
41
41
|
model_name: str = Field(..., min_length=1, description="Name of the model to use")
|
|
42
42
|
prompt: str = Field(..., description="Input prompt")
|
|
43
|
+
max_tokens: Optional[int] = Field(
|
|
44
|
+
default=None,
|
|
45
|
+
ge=1,
|
|
46
|
+
description=(
|
|
47
|
+
"Maximum number of tokens to generate. If None, server default applies."
|
|
48
|
+
),
|
|
49
|
+
)
|
|
43
50
|
localization: Optional[Dict[str, Any]] = Field(
|
|
44
51
|
default=None, description="Localization settings"
|
|
45
52
|
)
|
|
@@ -26,6 +26,7 @@ class GenerateTextRequestBuilder:
|
|
|
26
26
|
def __init__(self) -> None:
|
|
27
27
|
self._prompt = ""
|
|
28
28
|
self._model_name = ""
|
|
29
|
+
self._max_tokens: Optional[int] = None
|
|
29
30
|
self._localization: Optional[Dict[str, Any]] = None
|
|
30
31
|
self._tags: Optional[Dict[str, Any]] = None
|
|
31
32
|
|
|
@@ -37,6 +38,10 @@ class GenerateTextRequestBuilder:
|
|
|
37
38
|
self._model_name = model_name
|
|
38
39
|
return self
|
|
39
40
|
|
|
41
|
+
def set_max_tokens(self, max_tokens: int) -> "GenerateTextRequestBuilder":
|
|
42
|
+
self._max_tokens = max_tokens
|
|
43
|
+
return self
|
|
44
|
+
|
|
40
45
|
def set_localization(
|
|
41
46
|
self,
|
|
42
47
|
localization: Optional[Dict[str, Any]] = None,
|
|
@@ -75,6 +80,7 @@ class GenerateTextRequestBuilder:
|
|
|
75
80
|
request = GenerateTextRequest(
|
|
76
81
|
prompt=self._prompt,
|
|
77
82
|
model_name=self._model_name,
|
|
83
|
+
max_tokens=self._max_tokens,
|
|
78
84
|
localization=self._localization,
|
|
79
85
|
tags=self._tags,
|
|
80
86
|
)
|
|
@@ -21,14 +21,20 @@ from typing import (
|
|
|
21
21
|
Union,
|
|
22
22
|
)
|
|
23
23
|
|
|
24
|
-
from datacustomcode.common_config import
|
|
24
|
+
from datacustomcode.common_config import (
|
|
25
|
+
BaseConfig,
|
|
26
|
+
BaseObjectConfig,
|
|
27
|
+
default_config_file,
|
|
28
|
+
)
|
|
25
29
|
from datacustomcode.einstein_platform_config import CredentialsObjectConfig
|
|
26
30
|
from datacustomcode.llm_gateway.base import LLMGateway
|
|
31
|
+
from datacustomcode.llm_gateway.spark_base import SparkLLMGateway
|
|
27
32
|
|
|
28
33
|
_E = TypeVar("_E", bound=LLMGateway)
|
|
34
|
+
_S = TypeVar("_S", bound=SparkLLMGateway)
|
|
29
35
|
|
|
30
36
|
|
|
31
|
-
class LLMGatewayObjectConfig(CredentialsObjectConfig, Generic[_E]):
|
|
37
|
+
class LLMGatewayObjectConfig(CredentialsObjectConfig[_E], Generic[_E]):
|
|
32
38
|
type_to_create: ClassVar[Type[LLMGateway]] = LLMGateway # type: ignore[type-abstract]
|
|
33
39
|
|
|
34
40
|
|
|
@@ -52,6 +58,41 @@ class LLMGatewayConfig(BaseConfig):
|
|
|
52
58
|
return self
|
|
53
59
|
|
|
54
60
|
|
|
61
|
+
class SparkLLMGatewayObjectConfig(BaseObjectConfig, Generic[_S]):
|
|
62
|
+
type_to_create: ClassVar[Type[SparkLLMGateway]] = SparkLLMGateway # type: ignore[type-abstract]
|
|
63
|
+
|
|
64
|
+
def to_object(self) -> SparkLLMGateway:
|
|
65
|
+
type_ = self.type_to_create.subclass_from_config_name(self.type_config_name)
|
|
66
|
+
return type_(**self.options)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class SparkLLMGatewayConfig(BaseConfig):
|
|
70
|
+
spark_llm_gateway_config: Union[
|
|
71
|
+
SparkLLMGatewayObjectConfig[SparkLLMGateway], None
|
|
72
|
+
] = None
|
|
73
|
+
|
|
74
|
+
def update(self, other: "SparkLLMGatewayConfig") -> "SparkLLMGatewayConfig":
|
|
75
|
+
def merge(
|
|
76
|
+
config_a: Union[SparkLLMGatewayObjectConfig, None],
|
|
77
|
+
config_b: Union[SparkLLMGatewayObjectConfig, None],
|
|
78
|
+
) -> Union[SparkLLMGatewayObjectConfig, None]:
|
|
79
|
+
if config_a is not None and config_a.force:
|
|
80
|
+
return config_a
|
|
81
|
+
if config_b:
|
|
82
|
+
return config_b
|
|
83
|
+
return config_a
|
|
84
|
+
|
|
85
|
+
self.spark_llm_gateway_config = merge(
|
|
86
|
+
self.spark_llm_gateway_config, other.spark_llm_gateway_config
|
|
87
|
+
)
|
|
88
|
+
return self
|
|
89
|
+
|
|
90
|
+
|
|
55
91
|
# Global LLM Gateway config instance
|
|
56
92
|
llm_gateway_config = LLMGatewayConfig()
|
|
57
93
|
llm_gateway_config.load(default_config_file())
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
# Global Spark LLM Gateway config instance
|
|
97
|
+
spark_llm_gateway_config = SparkLLMGatewayConfig()
|
|
98
|
+
spark_llm_gateway_config.load(default_config_file())
|
|
@@ -7,6 +7,9 @@ This function demonstrates the new signature-based invocation with Pydantic mode
|
|
|
7
7
|
- Requires Runtime parameter (for agentic capabilities)
|
|
8
8
|
- Type-safe with direct field access (no wrappers)
|
|
9
9
|
- Automatic validation and conversion
|
|
10
|
+
|
|
11
|
+
You can use your AI models configured in Salesforce to generate texts.
|
|
12
|
+
See README.md for how to test locally before deploying to Data Cloud.
|
|
10
13
|
"""
|
|
11
14
|
|
|
12
15
|
import logging
|
|
@@ -12,6 +12,9 @@ Model: YH_Regression_Python_Predicted_SalePrice_CM_12l_ATC937af934
|
|
|
12
12
|
Type: Regression
|
|
13
13
|
Input: Year_Built__c (numeric)
|
|
14
14
|
Output: Predicted_SalePrice
|
|
15
|
+
|
|
16
|
+
You can use your AI models configured in Salesforce to make predictions.
|
|
17
|
+
See README.md for how to test locally before deploying to Data Cloud.
|
|
15
18
|
"""
|
|
16
19
|
|
|
17
20
|
import logging
|
|
@@ -65,13 +65,9 @@ def make_einstein_prediction(runtime: Runtime) -> None:
|
|
|
65
65
|
)
|
|
66
66
|
|
|
67
67
|
|
|
68
|
-
def generate_text(runtime: Runtime):
|
|
68
|
+
def generate_text(runtime: Runtime, prompt: str, model: str = "sfdc_ai__DefaultGPT52"):
|
|
69
69
|
builder = GenerateTextRequestBuilder()
|
|
70
|
-
llm_request = (
|
|
71
|
-
builder.set_prompt("Generate 2 dog names")
|
|
72
|
-
.set_model("sfdc_ai__DefaultGPT52")
|
|
73
|
-
.build()
|
|
74
|
-
)
|
|
70
|
+
llm_request = builder.set_prompt(prompt).set_model(model).build()
|
|
75
71
|
llm_response = runtime.llm_gateway.generate_text(llm_request)
|
|
76
72
|
logger.info(
|
|
77
73
|
f"LLM Gateway generate text results - success: [{llm_response.is_success}] "
|
|
@@ -88,13 +84,16 @@ def function(request: dict, runtime: Runtime) -> dict:
|
|
|
88
84
|
current_seq_no = 1 # Start sequence number from 1
|
|
89
85
|
|
|
90
86
|
"""
|
|
91
|
-
You can use your AI models configured in Salesforce
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
87
|
+
You can use your AI models configured in Salesforce to generate texts
|
|
88
|
+
or predict an outcome. See README.md for how to test locally before
|
|
89
|
+
deploying to Data Cloud.
|
|
90
|
+
|
|
91
|
+
Example:
|
|
92
|
+
|
|
93
|
+
>>> generated_text = generate_text(runtime, "Generate a greeting message")
|
|
94
|
+
... prediction = make_einstein_prediction(runtime)
|
|
95
|
+
|
|
95
96
|
"""
|
|
96
|
-
# generate_text(runtime)
|
|
97
|
-
# make_einstein_prediction(runtime)
|
|
98
97
|
|
|
99
98
|
for item in items:
|
|
100
99
|
# Item is DocElement as dict
|
|
@@ -12,6 +12,33 @@ def main():
|
|
|
12
12
|
# Perform transformations on the DataFrame
|
|
13
13
|
df_upper1 = df.withColumn("description__c", upper(col("description__c")))
|
|
14
14
|
|
|
15
|
+
"""
|
|
16
|
+
You can use your AI models configured in Salesforce to generate column
|
|
17
|
+
values. See README.md for how to test locally before deploying to Data Cloud.
|
|
18
|
+
|
|
19
|
+
Example:
|
|
20
|
+
|
|
21
|
+
>>> from datacustomcode.client import llm_gateway_generate_text_col
|
|
22
|
+
df_generated = df.withColumn(
|
|
23
|
+
... "greeting__c",
|
|
24
|
+
... llm_gateway_generate_text_col(
|
|
25
|
+
... "In one sentence, greet {name} from {city}.",
|
|
26
|
+
... {"name": col("name__c"), "city": col("homecity__c")},
|
|
27
|
+
... model_id="sfdc_ai__DefaultGPT4Omni",
|
|
28
|
+
... max_tokens=100,
|
|
29
|
+
... ),
|
|
30
|
+
... )
|
|
31
|
+
|
|
32
|
+
You can also invoke the LLM with a literal plain text prompt — no
|
|
33
|
+
``{field}`` substitution is performed on this string.
|
|
34
|
+
|
|
35
|
+
Example:
|
|
36
|
+
|
|
37
|
+
>>> generated_text = client.llm_gateway_generate_text(
|
|
38
|
+
... prompt, model_id, max_tokens
|
|
39
|
+
... )
|
|
40
|
+
"""
|
|
41
|
+
|
|
15
42
|
# Drop specific columns related to relationships
|
|
16
43
|
df_upper1 = df_upper1.drop("sfdcorganizationid__c")
|
|
17
44
|
df_upper1 = df_upper1.drop("kq_id__c")
|
datacustomcode/token_provider.py
CHANGED
|
@@ -101,75 +101,48 @@ class SFCLITokenProvider(TokenProvider):
|
|
|
101
101
|
|
|
102
102
|
from datacustomcode.deploy import AccessTokenResponse
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
f"'{description}' failed for org '{self.sf_cli_org}': "
|
|
126
|
-
f"{exc.stderr}"
|
|
127
|
-
) from exc
|
|
104
|
+
try:
|
|
105
|
+
result = subprocess.run(
|
|
106
|
+
["sf", "org", "display", "--target-org", self.sf_cli_org, "--json"],
|
|
107
|
+
capture_output=True,
|
|
108
|
+
text=True,
|
|
109
|
+
check=True,
|
|
110
|
+
timeout=30,
|
|
111
|
+
)
|
|
112
|
+
except FileNotFoundError as exc:
|
|
113
|
+
raise RuntimeError(
|
|
114
|
+
"The 'sf' command was not found. "
|
|
115
|
+
"Install Salesforce CLI: https://developer.salesforce.com/tools/salesforcecli"
|
|
116
|
+
) from exc
|
|
117
|
+
except subprocess.TimeoutExpired as exc:
|
|
118
|
+
raise RuntimeError(
|
|
119
|
+
f"'sf org display' timed out for org '{self.sf_cli_org}'"
|
|
120
|
+
) from exc
|
|
121
|
+
except subprocess.CalledProcessError as exc:
|
|
122
|
+
raise RuntimeError(
|
|
123
|
+
f"'sf org display' failed for org '{self.sf_cli_org}': {exc.stderr}"
|
|
124
|
+
) from exc
|
|
128
125
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
126
|
+
try:
|
|
127
|
+
data = json.loads(result.stdout)
|
|
128
|
+
except json.JSONDecodeError as exc:
|
|
129
|
+
raise RuntimeError(
|
|
130
|
+
f"Failed to parse JSON from 'sf org display': {result.stdout}"
|
|
131
|
+
) from exc
|
|
135
132
|
|
|
136
|
-
|
|
137
|
-
raise RuntimeError(
|
|
138
|
-
f"SF CLI error for org '{self.sf_cli_org}': "
|
|
139
|
-
f"{data.get('message', 'unknown error')}"
|
|
140
|
-
)
|
|
141
|
-
return dict(data)
|
|
142
|
-
|
|
143
|
-
# Get instanceUrl from sf org display
|
|
144
|
-
display_data = _run_sf_command(
|
|
145
|
-
["sf", "org", "display", "--target-org", self.sf_cli_org, "--json"],
|
|
146
|
-
"sf org display",
|
|
147
|
-
)
|
|
148
|
-
instance_url = display_data.get("result", {}).get("instanceUrl")
|
|
149
|
-
if not instance_url:
|
|
133
|
+
if data.get("status") != 0:
|
|
150
134
|
raise RuntimeError(
|
|
151
|
-
f"
|
|
152
|
-
f"
|
|
135
|
+
f"SF CLI error for org '{self.sf_cli_org}': "
|
|
136
|
+
f"{data.get('message', 'unknown error')}"
|
|
153
137
|
)
|
|
154
138
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
"org",
|
|
161
|
-
"auth",
|
|
162
|
-
"show-access-token",
|
|
163
|
-
"--target-org",
|
|
164
|
-
self.sf_cli_org,
|
|
165
|
-
"--json",
|
|
166
|
-
],
|
|
167
|
-
"sf org auth show-access-token",
|
|
168
|
-
)
|
|
169
|
-
access_token = token_data.get("result", {}).get("accessToken")
|
|
170
|
-
if not access_token:
|
|
139
|
+
result_data = data.get("result", {})
|
|
140
|
+
access_token = result_data.get("accessToken")
|
|
141
|
+
instance_url = result_data.get("instanceUrl")
|
|
142
|
+
|
|
143
|
+
if not access_token or not instance_url:
|
|
171
144
|
raise RuntimeError(
|
|
172
|
-
f"'sf org
|
|
145
|
+
f"'sf org display' did not return an access token or instance URL "
|
|
173
146
|
f"for org '{self.sf_cli_org}'"
|
|
174
147
|
)
|
|
175
148
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: salesforce-data-customcode
|
|
3
|
-
Version: 6.0.
|
|
3
|
+
Version: 6.0.2.dev1
|
|
4
4
|
Summary: Data Cloud Custom Code SDK
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
License-File: LICENSE.txt
|
|
@@ -330,6 +330,53 @@ Options:
|
|
|
330
330
|
- `--function-invoke-opt TEXT`: Currently we support only `UnstructuredChunking` for functions.
|
|
331
331
|
|
|
332
332
|
|
|
333
|
+
## Testing LLM Gateway
|
|
334
|
+
|
|
335
|
+
You can use AI models configured in Salesforce to generate responses while transforming your data. Below is a sample code example:
|
|
336
|
+
|
|
337
|
+
```
|
|
338
|
+
from datacustomcode.client import Client, llm_gateway_generate_text_col
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def main():
|
|
342
|
+
client = Client()
|
|
343
|
+
df = client.read_dlo("Input__dll")
|
|
344
|
+
df_generated = df.withColumn(
|
|
345
|
+
"greeting__c",
|
|
346
|
+
llm_gateway_generate_text_col(
|
|
347
|
+
"In one sentence, greet {name} from {city}.",
|
|
348
|
+
{"name": col("name__c"), "city": col("homecity__c")},
|
|
349
|
+
model_id="sfdc_ai__DefaultGPT4Omni", # An AI model in your org
|
|
350
|
+
max_tokens=100,
|
|
351
|
+
),
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
dlo_name = "Output_dll"
|
|
355
|
+
client.write_to_dlo(dlo_name, df_upper1, write_mode=WriteMode.APPEND)
|
|
356
|
+
|
|
357
|
+
greeting = client.llm_gateway_generate_text("In one sentence, generate a greeting message", "sfdc_ai__DefaultGPT52")
|
|
358
|
+
|
|
359
|
+
if __name__ == "__main__":
|
|
360
|
+
main()
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
In order to test this code on your local machine before deploying it to Data Cloud, you must first set up an External Client App that allows access to the Agent API. Follow this guide to create the ECA https://developer.salesforce.com/docs/ai/agentforce/guide/agent-api-get-started.html#create-a-salesforce-app. You must use `http://localhost:1717/OauthRedirect` as the callback URL.
|
|
364
|
+
|
|
365
|
+
Once the ECA is set up, log in to your org using this ECA
|
|
366
|
+
```
|
|
367
|
+
sf org login web \
|
|
368
|
+
--alias myorg \
|
|
369
|
+
--instance-url https://{MY_DOMAIN_URL} \
|
|
370
|
+
--client-id {CONSUMER_KEY} \
|
|
371
|
+
--scopes "sfap_api api"
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
then you can test your code using `myorg` alias
|
|
375
|
+
```
|
|
376
|
+
datacustomcode run ./payload/entrypoint.py --sf-cli-org myorg
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
|
|
333
380
|
## Docker usage
|
|
334
381
|
|
|
335
382
|
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.
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
datacustomcode/__init__.py,sha256=
|
|
1
|
+
datacustomcode/__init__.py,sha256=qx-X3U9lU_791ZbAxhGqQeyDw6eqTi9-E9AbYnwJfxU,2071
|
|
2
2
|
datacustomcode/auth.py,sha256=fpSjhIBdv9trC8yq2vuljAix_Euu-4Ah7HDCGhYjOxI,8309
|
|
3
3
|
datacustomcode/cli.py,sha256=ObqhOasZSZ8ZNFP6pywV3FpsUOz45_KaZdMNT4BHOKs,13069
|
|
4
|
-
datacustomcode/client.py,sha256=
|
|
4
|
+
datacustomcode/client.py,sha256=prAufc2_KAKdy0XX-nYhuD22a93GqQCsQuql9ru-8dY,13294
|
|
5
5
|
datacustomcode/cmd.py,sha256=ZMs46aydJw2EaU26JgCtZmnqESQFHvvaJz10hnjZTBk,3537
|
|
6
6
|
datacustomcode/common_config.py,sha256=SAUnxj3kqmOeWwPmFoYq4tuxokMgURVm4QwcGi-avL4,1928
|
|
7
7
|
datacustomcode/config.py,sha256=2Pk61ieQsEWSxKDxlS66_rliKE8iX0j-9LweEm0aaGo,4072
|
|
8
|
-
datacustomcode/config.yaml,sha256=
|
|
8
|
+
datacustomcode/config.yaml,sha256=Wd8Zd2f1__hRv7166H5IBbU5YoOEOdQNHgAb4ONbFnA,845
|
|
9
9
|
datacustomcode/constants.py,sha256=SskQpUPnQE7LjKh4Z3AdZ2p191_0Kf73jV8gdBXDPLU,1436
|
|
10
10
|
datacustomcode/credentials.py,sha256=D-7Zd3Nh_wStdj8_wUy5cnC8M_mdbfBijhIAi-2EbXs,9467
|
|
11
11
|
datacustomcode/deploy.py,sha256=9yaekNew5ha6bd6rIFERknFROomOeIfikrKXN6jCoq4,18811
|
|
12
12
|
datacustomcode/einstein_platform_client.py,sha256=ON2B_m--vdbCVVMVcLc81T-BRZ5-UuxVCer8E6OEQPA,4083
|
|
13
|
-
datacustomcode/einstein_platform_config.py,sha256=
|
|
13
|
+
datacustomcode/einstein_platform_config.py,sha256=6lb_FRbEzdt5a8-2cR15f13ZKw674uvRJ4Xq0o_pQXE,1490
|
|
14
14
|
datacustomcode/einstein_predictions/__init__.py,sha256=o-iask36phwGA7hGi_sxJpwbITO6h_STDe0J92qD2_M,859
|
|
15
15
|
datacustomcode/einstein_predictions/base.py,sha256=OBV445dpZRtCF5cpdHH49w_6RU_jZY1A-e7VtHTQCFU,1061
|
|
16
16
|
datacustomcode/einstein_predictions/impl/default.py,sha256=fEFhrosozhG0yT87w4Gu8wbe1NgHxBqdAduwWHdWGN4,3011
|
|
17
17
|
datacustomcode/einstein_predictions/types.py,sha256=W7H3sFzm_NdBtnia7O576w0OvM7jwzfGVQmFiZTO8Og,6098
|
|
18
|
-
datacustomcode/einstein_predictions_config.py,sha256=
|
|
18
|
+
datacustomcode/einstein_predictions_config.py,sha256=oxKgp2u7t5SdHVsasBBxsvd3KAfXuZ9uQXTrtpcCUlU,2135
|
|
19
19
|
datacustomcode/file/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
|
|
20
20
|
datacustomcode/file/base.py,sha256=2IUlQufPvpHccgyoeZlKhcktO4pS4NKdha03Whq33Zk,745
|
|
21
21
|
datacustomcode/file/path/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
|
|
@@ -23,7 +23,7 @@ datacustomcode/file/path/default.py,sha256=jyDv61JUlD5H6lUPAp55_B2toMryKItA8Hu2k
|
|
|
23
23
|
datacustomcode/function/__init__.py,sha256=oag8FevDxbx1vR0tFhtxPd5SvmUEYDj8esRo4v2qu3Q,749
|
|
24
24
|
datacustomcode/function/base.py,sha256=H_i80GcsFScvHJJ6bYLry5phTpsEU1KubpR8D3qnsjo,691
|
|
25
25
|
datacustomcode/function/feature_types/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
|
|
26
|
-
datacustomcode/function/feature_types/chunking.py,sha256=
|
|
26
|
+
datacustomcode/function/feature_types/chunking.py,sha256=_tCCHj7slD59-aLLEZUFRPOX37q_MEKkL4thi9CNwMw,7180
|
|
27
27
|
datacustomcode/function/runtime.py,sha256=jUduf-pve-0JAv0Lg0HPyLCZ9_Hgcxe25dI7t-DgX9o,3696
|
|
28
28
|
datacustomcode/function_utils.py,sha256=y6vaoSSaJ9CeHhjLCNyqzJT4vx6yCePWRxNLz38ddjQ,12920
|
|
29
29
|
datacustomcode/io/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
|
|
@@ -37,20 +37,18 @@ datacustomcode/io/writer/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSat
|
|
|
37
37
|
datacustomcode/io/writer/base.py,sha256=RHafJ-Xmh_TnYcN4QfSh0VdIZeIevKmz9sf05adMgxA,1540
|
|
38
38
|
datacustomcode/io/writer/csv.py,sha256=asty5teBpNQ1fMGHZ7wA3suLhq0sk0lVQPN5x7TOSRk,1555
|
|
39
39
|
datacustomcode/io/writer/print.py,sha256=0g2sP_1Wb95UIyEELWJt3dqM18Iv_CWhDW3mDxcIhns,5105
|
|
40
|
-
datacustomcode/llm_gateway/__init__.py,sha256=
|
|
40
|
+
datacustomcode/llm_gateway/__init__.py,sha256=ZYEMvQlnWzdSdBwYrhBQGmlfBBqsfmhAy4KViyCBFVA,995
|
|
41
41
|
datacustomcode/llm_gateway/base.py,sha256=CTUhZiZ0JFlmWj6kQpTR4_-mUvqkBKl_Fkdvv9VwxY8,1262
|
|
42
|
-
datacustomcode/llm_gateway/default.py,sha256=
|
|
42
|
+
datacustomcode/llm_gateway/default.py,sha256=HVUc5NihNAQMVgRAJ8w2CBDX4mRLl8FRkpCJWv9FAOU,1952
|
|
43
|
+
datacustomcode/llm_gateway/spark_base.py,sha256=h9fBrhBSSthCMBi6DjryxMKp_WSLdoMDg6a3FgO4oKI,1637
|
|
44
|
+
datacustomcode/llm_gateway/spark_default.py,sha256=2-u9Oy936kj35wv8_qBSc-xtqnC7WNkgprhcuroP7U8,3524
|
|
43
45
|
datacustomcode/llm_gateway/types/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
|
|
44
|
-
datacustomcode/llm_gateway/types/generate_text_request.py,sha256=
|
|
45
|
-
datacustomcode/llm_gateway/types/generate_text_request_builder.py,sha256=
|
|
46
|
+
datacustomcode/llm_gateway/types/generate_text_request.py,sha256=pHFp9r12xT_GlFm873kQEfrHCdoJI5sJGrCRVqqN3vg,1647
|
|
47
|
+
datacustomcode/llm_gateway/types/generate_text_request_builder.py,sha256=P2lBwyjGQvqf8G9PR4pNeN02AeYri1XCOvlBeRqAJNw,2791
|
|
46
48
|
datacustomcode/llm_gateway/types/generate_text_response.py,sha256=NSvj6nvzR4cZ0cVs2-PE9Ct3ZY-xL4MQYknJMd_xdDI,1912
|
|
47
49
|
datacustomcode/llm_gateway/types/generate_text_response_builder.py,sha256=6MV6JZuTyHUId3Slw9k7m0KBgjj-5S9HI4qtd94Jl2A,1272
|
|
48
|
-
datacustomcode/llm_gateway_config.py,sha256=
|
|
50
|
+
datacustomcode/llm_gateway_config.py,sha256=ECm9CFqOFOaLHwenvVFAjiRSzG9Eg9fY4pb8nHbQ34c,3312
|
|
49
51
|
datacustomcode/mixin.py,sha256=ZtROqO1W1_D7MV8lw4cw6zzcchJLoZS0aAiXrolYR4k,4914
|
|
50
|
-
datacustomcode/proxy/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
|
|
51
|
-
datacustomcode/proxy/base.py,sha256=Gw8of0cBgcOSpjnR7PX8pqWnsjHpt1AgKIK7u6k6DBU,846
|
|
52
|
-
datacustomcode/proxy/client/__init__.py,sha256=gamfOD1VnAtEslRBpqh-yKiVjkG_wYWYdSatGIfsN-w,621
|
|
53
|
-
datacustomcode/proxy/client/base.py,sha256=dWFcc5_5vSBxZmo7k5cwKnJl1_gcjvOZYI2EjBUXuaA,1073
|
|
54
52
|
datacustomcode/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
55
53
|
datacustomcode/run.py,sha256=78IpkuEih3GCO6sQPZLFfiKnrCI-eMtEMLsj-1vUvSE,7362
|
|
56
54
|
datacustomcode/scan.py,sha256=Zb9mE733H_xaqyDI-LZjjnIcctMC9j1AaD_kcr9qTh4,14325
|
|
@@ -67,14 +65,14 @@ datacustomcode/templates/function/chunking/payload/config.json,sha256=RBNvo1WzZ4
|
|
|
67
65
|
datacustomcode/templates/function/chunking/payload/entrypoint.py,sha256=tzpQJjODulwzLilOoKdOo8GjpdIlCDByjnawpHIQYQA,4517
|
|
68
66
|
datacustomcode/templates/function/chunking/requirements.txt,sha256=Ih0KsVdiTdo7KuIsqFB_AJMRT2r0ao_xDEb3hiDmf48,46
|
|
69
67
|
datacustomcode/templates/function/example/chunking_with_llm/config.json,sha256=EvjuOVssRg2SjcUb5F50RRMGDqag_f69bv8AOflaK1g,38
|
|
70
|
-
datacustomcode/templates/function/example/chunking_with_llm/entrypoint.py,sha256=
|
|
68
|
+
datacustomcode/templates/function/example/chunking_with_llm/entrypoint.py,sha256=6AMVf_busCCDALktG8vkCtjnzJheMgM-OOLML5iLKOg,3437
|
|
71
69
|
datacustomcode/templates/function/example/chunking_with_llm/files/chunking_prompt.txt,sha256=w_gSYNXwZmbMTMjZ_YYwm1IpMsVpI3hyC3ew60zqs_0,446
|
|
72
70
|
datacustomcode/templates/function/example/chunking_with_llm/tests/test.json,sha256=ZcH6QGEWu03dc922Za3vdx6hJY08nfGPie9kkeup-sc,9457
|
|
73
71
|
datacustomcode/templates/function/example/chunking_with_prediction/config.json,sha256=EvjuOVssRg2SjcUb5F50RRMGDqag_f69bv8AOflaK1g,38
|
|
74
|
-
datacustomcode/templates/function/example/chunking_with_prediction/entrypoint.py,sha256=
|
|
72
|
+
datacustomcode/templates/function/example/chunking_with_prediction/entrypoint.py,sha256=w25_WucA-tUN3O6j-Od_WsW4HDH1Dfp2uJYNfVs_0M4,7722
|
|
75
73
|
datacustomcode/templates/function/example/chunking_with_prediction/tests/test.json,sha256=2EE0c0n-s6eOayb_JrBqeKkXzyxieOyHK3_Mbm--Nmo,1073
|
|
76
74
|
datacustomcode/templates/function/payload/config.json,sha256=RBNvo1WzZ4oRRq0W9-hknpT7T8If536DEMBg9hyq_4o,2
|
|
77
|
-
datacustomcode/templates/function/payload/entrypoint.py,sha256=
|
|
75
|
+
datacustomcode/templates/function/payload/entrypoint.py,sha256=uWb9mT7GaOvVWBK8P7vHS1GNbNaH--rSLV8J1v0eTHY,5667
|
|
78
76
|
datacustomcode/templates/function/requirements-dev.txt,sha256=qT2-m2FOgiYPTvqaNy0yRzIAXqHgR5b8stccYXsXVi8,88
|
|
79
77
|
datacustomcode/templates/function/requirements.txt,sha256=qJbqzs5z0Hrx590U3T7dHq_m8UQEx2TdhgrJSz-QHIQ,40
|
|
80
78
|
datacustomcode/templates/script/.devcontainer/devcontainer.json,sha256=lWMFk-SdTKBlQt_VJrMn8gZPmvT4tfcjRpCNhLdElZc,167
|
|
@@ -87,13 +85,13 @@ datacustomcode/templates/script/examples/employee_hierarchy/employee_data.csv,sh
|
|
|
87
85
|
datacustomcode/templates/script/examples/employee_hierarchy/entrypoint.py,sha256=Mfm3iQtEHTQRW6cmZTwRKdTh3IeGWR-teXrd6x-YLSY,2223
|
|
88
86
|
datacustomcode/templates/script/jupyterlab.sh,sha256=IHR3YQ8d_busuyvesByhJgzCKULIFPI-Hqogs0NPhCs,2432
|
|
89
87
|
datacustomcode/templates/script/payload/config.json,sha256=0d2mEMt4NHIeOUTsgiPMuRKdOLIQxmh-Wq-IfEqU-gc,28
|
|
90
|
-
datacustomcode/templates/script/payload/entrypoint.py,sha256=
|
|
88
|
+
datacustomcode/templates/script/payload/entrypoint.py,sha256=HFrTe7--w5X78Sh4DVkoGGR6-zeqxemqp80RM20Rr4k,1642
|
|
91
89
|
datacustomcode/templates/script/requirements-dev.txt,sha256=OWwuy1awesqOZOS3Zizmdd6BDnSePpGFN5bq5IrALvc,176
|
|
92
90
|
datacustomcode/templates/script/requirements.txt,sha256=qJbqzs5z0Hrx590U3T7dHq_m8UQEx2TdhgrJSz-QHIQ,40
|
|
93
|
-
datacustomcode/token_provider.py,sha256=
|
|
91
|
+
datacustomcode/token_provider.py,sha256=KPj_ca6mcBmhXHaPmZjAI4it8QvOWdwKJL8yfqxfYwU,5446
|
|
94
92
|
datacustomcode/version.py,sha256=9LlbVrzwBvut1L308QbwNBgxdQk5CrghH39JARVSxms,989
|
|
95
|
-
salesforce_data_customcode-6.0.
|
|
96
|
-
salesforce_data_customcode-6.0.
|
|
97
|
-
salesforce_data_customcode-6.0.
|
|
98
|
-
salesforce_data_customcode-6.0.
|
|
99
|
-
salesforce_data_customcode-6.0.
|
|
93
|
+
salesforce_data_customcode-6.0.2.dev1.dist-info/METADATA,sha256=8lK5D1Zf3TelM0vlib8QBQLtdmixh79g4ce2Owuh8QQ,21748
|
|
94
|
+
salesforce_data_customcode-6.0.2.dev1.dist-info/WHEEL,sha256=eY7nduwzv-ldUxpzbRlxwvC693Hg6PX8bWDjEHjZ_dk,88
|
|
95
|
+
salesforce_data_customcode-6.0.2.dev1.dist-info/entry_points.txt,sha256=WpQ94UB7UuRCYGOLtJV3vAgm1tl7iVf43VYRWIuNu5Y,74
|
|
96
|
+
salesforce_data_customcode-6.0.2.dev1.dist-info/licenses/LICENSE.txt,sha256=iOi8EmQpfkFhMENi7VYtkl2EqS14pEOccoXHiW2dyPU,11443
|
|
97
|
+
salesforce_data_customcode-6.0.2.dev1.dist-info/RECORD,,
|
datacustomcode/proxy/__init__.py
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
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.
|
datacustomcode/proxy/base.py
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
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
|
|
18
|
-
|
|
19
|
-
from datacustomcode.mixin import UserExtendableNamedConfigMixin
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class BaseProxyAccessLayer(ABC, UserExtendableNamedConfigMixin):
|
|
23
|
-
def __init__(self):
|
|
24
|
-
pass
|
|
@@ -1,14 +0,0 @@
|
|
|
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.
|
|
@@ -1,32 +0,0 @@
|
|
|
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 abstractmethod
|
|
18
|
-
|
|
19
|
-
from datacustomcode.proxy.base import BaseProxyAccessLayer
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class BaseProxyClient(BaseProxyAccessLayer):
|
|
23
|
-
def __init__(self):
|
|
24
|
-
pass
|
|
25
|
-
|
|
26
|
-
@abstractmethod
|
|
27
|
-
def call_llm_gateway(self, llmModelId: str, prompt: str, maxTokens: int) -> str: ...
|
|
28
|
-
|
|
29
|
-
@abstractmethod
|
|
30
|
-
def llm_gateway_generate_text(
|
|
31
|
-
self, template, values, llmModelId: str, maxTokens: int
|
|
32
|
-
): ...
|
|
File without changes
|
|
File without changes
|