select-ai 1.0.0__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.

Potentially problematic release.


This version of select-ai might be problematic. Click here for more details.

select_ai/provider.py ADDED
@@ -0,0 +1,293 @@
1
+ # -----------------------------------------------------------------------------
2
+ # Copyright (c) 2025, Oracle and/or its affiliates.
3
+ #
4
+ # Licensed under the Universal Permissive License v 1.0 as shown at
5
+ # http://oss.oracle.com/licenses/upl.
6
+ # -----------------------------------------------------------------------------
7
+
8
+ from dataclasses import dataclass
9
+ from typing import List, Optional, Union
10
+
11
+ from select_ai._abc import SelectAIDataClass
12
+ from select_ai._validations import enforce_types
13
+
14
+ from .db import async_cursor, cursor
15
+ from .sql import (
16
+ DISABLE_AI_PROFILE_DOMAIN_FOR_USER,
17
+ ENABLE_AI_PROFILE_DOMAIN_FOR_USER,
18
+ GRANT_PRIVILEGES_TO_USER,
19
+ REVOKE_PRIVILEGES_FROM_USER,
20
+ )
21
+
22
+ OPENAI = "openai"
23
+ COHERE = "cohere"
24
+ AZURE = "azure"
25
+ OCI = "oci"
26
+ GOOGLE = "google"
27
+ ANTHROPIC = "anthropic"
28
+ HUGGINGFACE = "huggingface"
29
+ AWS = "aws"
30
+
31
+
32
+ @dataclass
33
+ class Provider(SelectAIDataClass):
34
+ """
35
+ Base class for AI Provider
36
+
37
+ To create an object of Provider class, use any one of the concrete AI
38
+ provider implementations
39
+
40
+ :param str embedding_model: The embedding model, also known as a
41
+ transformer. Depending on the AI provider, the supported embedding models
42
+ vary
43
+ :param str model: The name of the LLM being used to generate
44
+ responses
45
+ :param str provider_name: The name of the provider being used
46
+ :param str provider_endpoint: Endpoint URL of the AI provider being used
47
+ :param str region: The cloud region of the Gen AI cluster
48
+
49
+ """
50
+
51
+ embedding_model: Optional[str] = None
52
+ model: Optional[str] = None
53
+ provider_name: Optional[str] = None
54
+ provider_endpoint: Optional[str] = None
55
+ region: Optional[str] = None
56
+
57
+ @classmethod
58
+ def create(cls, *, provider_name: Optional[str] = None, **kwargs):
59
+ for subclass in cls.__subclasses__():
60
+ if subclass.provider_name == provider_name:
61
+ return subclass(**kwargs)
62
+ return cls(**kwargs)
63
+
64
+ @classmethod
65
+ def key_alias(cls, k):
66
+ return {"provider": "provider_name", "provider_name": "provider"}.get(
67
+ k, k
68
+ )
69
+
70
+ @classmethod
71
+ def keys(cls):
72
+ return {
73
+ "provider",
74
+ "provider_name",
75
+ "embedding_model",
76
+ "model",
77
+ "region",
78
+ "provider_endpoint",
79
+ "azure_deployment_name",
80
+ "azure_embedding_deployment_name",
81
+ "azure_resource_name",
82
+ "oci_apiformat",
83
+ "oci_compartment_id",
84
+ "oci_endpoint_id",
85
+ "oci_runtimetype",
86
+ "aws_apiformat",
87
+ }
88
+
89
+
90
+ @dataclass
91
+ class AzureProvider(Provider):
92
+ """
93
+ Azure specific attributes
94
+
95
+ :param str azure_deployment_name: Name of the Azure OpenAI Service
96
+ deployed model.
97
+ :param str azure_embedding_deployment_name: Name of the Azure OpenAI
98
+ deployed embedding model.
99
+ :param str azure_resource_name: Name of the Azure OpenAI Service resource
100
+ """
101
+
102
+ provider_name: str = AZURE
103
+ azure_deployment_name: Optional[str] = None
104
+ azure_embedding_deployment_name: Optional[str] = None
105
+ azure_resource_name: Optional[str] = None
106
+
107
+ def __post_init__(self):
108
+ super().__post_init__()
109
+ self.provider_endpoint = f"{self.azure_resource_name}.openai.azure.com"
110
+
111
+
112
+ @dataclass
113
+ class OpenAIProvider(Provider):
114
+ """
115
+ OpenAI specific attributes
116
+ """
117
+
118
+ provider_name: str = OPENAI
119
+ provider_endpoint: Optional[str] = "api.openai.com"
120
+
121
+
122
+ @dataclass
123
+ class OCIGenAIProvider(Provider):
124
+ """
125
+ OCI Gen AI specific attributes
126
+
127
+ :param str oci_apiformat: Specifies the format in which the API expects
128
+ data to be sent and received. Supported values are 'COHERE' and 'GENERIC'
129
+ :param str oci_compartment_id: Specifies the OCID of the compartment you
130
+ are permitted to access when calling the OCI Generative AI service
131
+ :param str oci_endpoint_id: This attributes indicates the endpoint OCID
132
+ of the Oracle dedicated AI hosting cluster
133
+ :param str oci_runtimetype: This attribute indicates the runtime type of
134
+ the provided model. The supported values are 'COHERE' and 'LLAMA'
135
+ """
136
+
137
+ provider_name: str = OCI
138
+ oci_apiformat: Optional[str] = None
139
+ oci_compartment_id: Optional[str] = None
140
+ oci_endpoint_id: Optional[str] = None
141
+ oci_runtimetype: Optional[str] = None
142
+
143
+
144
+ @dataclass
145
+ class CohereProvider(Provider):
146
+ """
147
+ Cohere AI specific attributes
148
+ """
149
+
150
+ provider_name: str = COHERE
151
+ provider_endpoint = "api.cohere.ai"
152
+
153
+
154
+ @dataclass
155
+ class GoogleProvider(Provider):
156
+ """
157
+ Google AI specific attributes
158
+ """
159
+
160
+ provider_name: str = GOOGLE
161
+ provider_endpoint = "generativelanguage.googleapis.com"
162
+
163
+
164
+ @dataclass
165
+ class HuggingFaceProvider(Provider):
166
+ """
167
+ HuggingFace specific attributes
168
+ """
169
+
170
+ provider_name: str = HUGGINGFACE
171
+ provider_endpoint = "api-inference.huggingface.co"
172
+
173
+
174
+ @dataclass
175
+ class AWSProvider(Provider):
176
+ """
177
+ AWS specific attributes
178
+ """
179
+
180
+ provider_name: str = AWS
181
+ aws_apiformat: Optional[str] = None
182
+
183
+ def __post_init__(self):
184
+ super().__post_init__()
185
+ self.provider_endpoint = f"bedrock-runtime.{self.region}.amazonaws.com"
186
+
187
+
188
+ @dataclass
189
+ class AnthropicProvider(Provider):
190
+ """
191
+ Anthropic specific attributes
192
+ """
193
+
194
+ provider_name: str = ANTHROPIC
195
+ provider_endpoint = "api.anthropic.com"
196
+
197
+
198
+ @enforce_types
199
+ async def async_enable_provider(
200
+ users: Union[str, List[str]], provider_endpoint: str = None
201
+ ):
202
+ """
203
+ Async API to enable AI profile for database users.
204
+
205
+ This method grants execute privilege on the packages DBMS_CLOUD,
206
+ DBMS_CLOUD_AI and DBMS_CLOUD_PIPELINE. It also enables the database
207
+ user to invoke the AI Provider (LLM) endpoint
208
+
209
+ """
210
+ if isinstance(users, str):
211
+ users = [users]
212
+
213
+ async with async_cursor() as cr:
214
+ for user in users:
215
+ await cr.execute(GRANT_PRIVILEGES_TO_USER.format(user.strip()))
216
+ if provider_endpoint:
217
+ await cr.execute(
218
+ ENABLE_AI_PROFILE_DOMAIN_FOR_USER,
219
+ user=user,
220
+ host=provider_endpoint,
221
+ )
222
+
223
+
224
+ @enforce_types
225
+ async def async_disable_provider(
226
+ users: Union[str, List[str]], provider_endpoint: str = None
227
+ ):
228
+ """
229
+ Async API to disable AI profile for database users
230
+
231
+ Disables AI provider for the user. This method revokes execute privilege
232
+ on the packages DBMS_CLOUD, DBMS_CLOUD_AI and DBMS_CLOUD_PIPELINE. It
233
+ also disables the user to invoke the AI Provider (LLM) endpoint
234
+ """
235
+ if isinstance(users, str):
236
+ users = [users]
237
+
238
+ async with async_cursor() as cr:
239
+ for user in users:
240
+ await cr.execute(REVOKE_PRIVILEGES_FROM_USER.format(user.strip()))
241
+ if provider_endpoint:
242
+ await cr.execute(
243
+ DISABLE_AI_PROFILE_DOMAIN_FOR_USER,
244
+ user=user,
245
+ host=provider_endpoint,
246
+ )
247
+
248
+
249
+ @enforce_types
250
+ def enable_provider(
251
+ users: Union[str, List[str]], provider_endpoint: str = None
252
+ ):
253
+ """
254
+ Enables AI profile for the user. This method grants execute privilege
255
+ on the packages DBMS_CLOUD, DBMS_CLOUD_AI and DBMS_CLOUD_PIPELINE. It
256
+ also enables the user to invoke the AI Provider (LLM) endpoint
257
+ """
258
+ if isinstance(users, str):
259
+ users = [users]
260
+
261
+ with cursor() as cr:
262
+ for user in users:
263
+ cr.execute(GRANT_PRIVILEGES_TO_USER.format(user.strip()))
264
+ if provider_endpoint:
265
+ cr.execute(
266
+ ENABLE_AI_PROFILE_DOMAIN_FOR_USER,
267
+ user=user,
268
+ host=provider_endpoint,
269
+ )
270
+
271
+
272
+ @enforce_types
273
+ def disable_provider(
274
+ users: Union[str, List[str]], provider_endpoint: str = None
275
+ ):
276
+ """
277
+ Disables AI provider for the user. This method revokes execute privilege
278
+ on the packages DBMS_CLOUD, DBMS_CLOUD_AI and DBMS_CLOUD_PIPELINE. It
279
+ also disables the user to invoke the AI(LLM) endpoint
280
+
281
+ """
282
+ if isinstance(users, str):
283
+ users = [users]
284
+
285
+ with cursor() as cr:
286
+ for user in users:
287
+ cr.execute(REVOKE_PRIVILEGES_FROM_USER.format(user.strip()))
288
+ if provider_endpoint:
289
+ cr.execute(
290
+ DISABLE_AI_PROFILE_DOMAIN_FOR_USER,
291
+ user=user,
292
+ host=provider_endpoint,
293
+ )
select_ai/sql.py ADDED
@@ -0,0 +1,105 @@
1
+ # -----------------------------------------------------------------------------
2
+ # Copyright (c) 2025, Oracle and/or its affiliates.
3
+ #
4
+ # Licensed under the Universal Permissive License v 1.0 as shown at
5
+ # http://oss.oracle.com/licenses/upl.
6
+ # -----------------------------------------------------------------------------
7
+
8
+ GRANT_PRIVILEGES_TO_USER = """
9
+ DECLARE
10
+ TYPE array_t IS VARRAY(3) OF VARCHAR2(60);
11
+ v_packages array_t;
12
+ BEGIN
13
+ v_packages := array_t(
14
+ 'DBMS_CLOUD', 'DBMS_CLOUD_AI', 'DBMS_CLOUD_PIPELINE'
15
+ );
16
+ FOR i in 1..v_packages.count LOOP
17
+ EXECUTE IMMEDIATE
18
+ 'GRANT EXECUTE ON ' || v_packages(i) || ' TO {0}';
19
+ END LOOP;
20
+ END;
21
+ """
22
+
23
+ REVOKE_PRIVILEGES_FROM_USER = """
24
+ DECLARE
25
+ TYPE array_t IS VARRAY(3) OF VARCHAR2(60);
26
+ v_packages array_t;
27
+ BEGIN
28
+ v_packages := array_t(
29
+ 'DBMS_CLOUD', 'DBMS_CLOUD_AI', 'DBMS_CLOUD_PIPELINE'
30
+ );
31
+ FOR i in 1..v_packages.count LOOP
32
+ EXECUTE IMMEDIATE
33
+ 'REVOKE EXECUTE ON ' || v_packages(i) || ' FROM {0}';
34
+ END LOOP;
35
+ END;
36
+ """
37
+
38
+ ENABLE_AI_PROFILE_DOMAIN_FOR_USER = """
39
+ BEGIN
40
+ DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE(
41
+ host => :host,
42
+ ace => xs$ace_type(privilege_list => xs$name_list('http'),
43
+ principal_name => :user,
44
+ principal_type => xs_acl.ptype_db)
45
+ );
46
+ END;
47
+ """
48
+
49
+ DISABLE_AI_PROFILE_DOMAIN_FOR_USER = """
50
+ BEGIN
51
+ DBMS_NETWORK_ACL_ADMIN.REMOVE_HOST_ACE(
52
+ host => :host,
53
+ ace => xs$ace_type(privilege_list => xs$name_list('http'),
54
+ principal_name => :user,
55
+ principal_type => xs_acl.ptype_db)
56
+ );
57
+ END;
58
+ """
59
+
60
+ GET_USER_AI_PROFILE_ATTRIBUTES = """
61
+ SELECT attribute_name, attribute_value
62
+ FROM USER_CLOUD_AI_PROFILE_ATTRIBUTES
63
+ WHERE profile_name = :profile_name
64
+ """
65
+
66
+ GET_USER_AI_PROFILE = """
67
+ SELECT profile_name, description
68
+ FROM USER_CLOUD_AI_PROFILES
69
+ WHERE profile_name = :profile_name
70
+ """
71
+
72
+
73
+ LIST_USER_AI_PROFILES = """
74
+ SELECT profile_name, description
75
+ FROM USER_CLOUD_AI_PROFILES
76
+ WHERE REGEXP_LIKE(profile_name, :profile_name_pattern, 'i')
77
+ """
78
+
79
+ LIST_USER_VECTOR_INDEXES = """
80
+ SELECT v.index_name, v.description
81
+ FROM USER_CLOUD_VECTOR_INDEXES v
82
+ WHERE REGEXP_LIKE(v.index_name, :index_name_pattern, 'i')
83
+ """
84
+
85
+ GET_USER_VECTOR_INDEX_ATTRIBUTES = """
86
+ SELECT attribute_name, attribute_value
87
+ FROM USER_CLOUD_VECTOR_INDEX_ATTRIBUTES
88
+ WHERE INDEX_NAME = :index_name
89
+ """
90
+
91
+ LIST_USER_CONVERSATIONS = """
92
+ SELECT conversation_id,
93
+ conversation_title,
94
+ description,
95
+ retention_days
96
+ from USER_CLOUD_AI_CONVERSATIONS
97
+ """
98
+
99
+ GET_USER_CONVERSATION_ATTRIBUTES = """
100
+ SELECT conversation_title,
101
+ description,
102
+ retention_days
103
+ from USER_CLOUD_AI_CONVERSATIONS
104
+ WHERE conversation_id = :conversation_id
105
+ """
@@ -0,0 +1,90 @@
1
+ # -----------------------------------------------------------------------------
2
+ # Copyright (c) 2025, Oracle and/or its affiliates.
3
+ #
4
+ # Licensed under the Universal Permissive License v 1.0 as shown at
5
+ # http://oss.oracle.com/licenses/upl.
6
+ # -----------------------------------------------------------------------------
7
+
8
+ import json
9
+ from dataclasses import dataclass
10
+ from typing import List, Mapping, Optional
11
+
12
+ from select_ai._abc import SelectAIDataClass
13
+
14
+
15
+ @dataclass
16
+ class SyntheticDataParams(SelectAIDataClass):
17
+ """Optional parameters to control generation of synthetic data
18
+
19
+ :param int sample_rows: number of rows from the table to use as a sample
20
+ to guide the LLM in data generation
21
+
22
+ :param bool table_statistics: Enable or disable the use of table
23
+ statistics information. Default value is False
24
+
25
+ :param str priority: Assign a priority value that defines the number of
26
+ parallel requests sent to the LLM for generating synthetic data.
27
+ Tasks with a higher priority will consume more database resources and
28
+ complete faster. Possible values are: HIGH, MEDIUM, LOW
29
+
30
+ :param bool comments: Enable or disable sending comments to the LLM to
31
+ guide data generation. Default value is False
32
+
33
+ """
34
+
35
+ sample_rows: Optional[int] = None
36
+ table_statistics: Optional[bool] = False
37
+ priority: Optional[str] = "HIGH"
38
+ comments: Optional[bool] = False
39
+
40
+
41
+ @dataclass
42
+ class SyntheticDataAttributes(SelectAIDataClass):
43
+ """Attributes to control generation of synthetic data
44
+
45
+ :param str object_name: Table name to populate synthetic data
46
+ :param List[Mapping] object_list: Use this to generate synthetic data
47
+ on multiple tables
48
+ :param str owner_name: Database user who owns the referenced object.
49
+ Default value is connected user's schema
50
+ :param int record_count: Number of records to generate
51
+ :param str user_prompt: User prompt to guide generation of synthetic data
52
+ For e.g. "the release date for the movies should be in 2019"
53
+
54
+ """
55
+
56
+ object_name: Optional[str] = None
57
+ object_list: Optional[List[Mapping]] = None
58
+ owner_name: Optional[str] = None
59
+ params: Optional[SyntheticDataParams] = None
60
+ record_count: Optional[int] = None
61
+ user_prompt: Optional[str] = None
62
+
63
+ def __post_init__(self):
64
+ if self.params and not isinstance(self.params, SyntheticDataParams):
65
+ raise TypeError(
66
+ "'params' must be an object of" " type SyntheticDataParams'"
67
+ )
68
+
69
+ def dict(self, exclude_null=True):
70
+ attributes = {}
71
+ for k, v in self.__dict__.items():
72
+ if v is not None or not exclude_null:
73
+ if isinstance(v, SyntheticDataParams):
74
+ attributes[k] = v.json(exclude_null=exclude_null)
75
+ elif isinstance(v, List):
76
+ attributes[k] = json.dumps(v)
77
+ else:
78
+ attributes[k] = v
79
+ return attributes
80
+
81
+ def prepare(self):
82
+ if self.object_name and self.object_list:
83
+ raise ValueError("Both object_name and object_list cannot be set")
84
+
85
+ if not self.object_name and not self.object_list:
86
+ raise ValueError(
87
+ "One of object_name and object_list should be set"
88
+ )
89
+
90
+ return self.dict()