select-ai 1.0.0b1__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,288 @@
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
+
13
+ from .db import async_cursor, cursor
14
+ from .sql import (
15
+ DISABLE_AI_PROFILE_DOMAIN_FOR_USER,
16
+ ENABLE_AI_PROFILE_DOMAIN_FOR_USER,
17
+ GRANT_PRIVILEGES_TO_USER,
18
+ REVOKE_PRIVILEGES_FROM_USER,
19
+ )
20
+
21
+ OPENAI = "openai"
22
+ COHERE = "cohere"
23
+ AZURE = "azure"
24
+ OCI = "oci"
25
+ GOOGLE = "google"
26
+ ANTHROPIC = "anthropic"
27
+ HUGGINGFACE = "huggingface"
28
+ AWS = "aws"
29
+
30
+
31
+ @dataclass
32
+ class Provider(SelectAIDataClass):
33
+ """
34
+ Base class for AI Provider
35
+
36
+ To create an object of Provider class, use any one of the concrete AI
37
+ provider implementations
38
+
39
+ :param str embedding_model: The embedding model, also known as a
40
+ transformer. Depending on the AI provider, the supported embedding models
41
+ vary
42
+ :param str model: The name of the LLM being used to generate
43
+ responses
44
+ :param str provider_name: The name of the provider being used
45
+ :param str provider_endpoint: Endpoint URL of the AI provider being used
46
+ :param str region: The cloud region of the Gen AI cluster
47
+
48
+ """
49
+
50
+ embedding_model: Optional[str] = None
51
+ model: Optional[str] = None
52
+ provider_name: Optional[str] = None
53
+ provider_endpoint: Optional[str] = None
54
+ region: Optional[str] = None
55
+
56
+ @classmethod
57
+ def create(cls, *, provider_name: Optional[str] = None, **kwargs):
58
+ for subclass in cls.__subclasses__():
59
+ if subclass.provider_name == provider_name:
60
+ return subclass(**kwargs)
61
+ return cls(**kwargs)
62
+
63
+ @classmethod
64
+ def key_alias(cls, k):
65
+ return {"provider": "provider_name", "provider_name": "provider"}.get(
66
+ k, k
67
+ )
68
+
69
+ @classmethod
70
+ def keys(cls):
71
+ return {
72
+ "provider",
73
+ "provider_name",
74
+ "embedding_model",
75
+ "model",
76
+ "region",
77
+ "provider_endpoint",
78
+ "azure_deployment_name",
79
+ "azure_embedding_deployment_name",
80
+ "azure_resource_name",
81
+ "oci_apiformat",
82
+ "oci_compartment_id",
83
+ "oci_endpoint_id",
84
+ "oci_runtimetype",
85
+ "aws_apiformat",
86
+ }
87
+
88
+
89
+ @dataclass
90
+ class AzureProvider(Provider):
91
+ """
92
+ Azure specific attributes
93
+
94
+ :param str azure_deployment_name: Name of the Azure OpenAI Service
95
+ deployed model.
96
+ :param str azure_embedding_deployment_name: Name of the Azure OpenAI
97
+ deployed embedding model.
98
+ :param str azure_resource_name: Name of the Azure OpenAI Service resource
99
+ """
100
+
101
+ provider_name: str = AZURE
102
+ azure_deployment_name: Optional[str] = None
103
+ azure_embedding_deployment_name: Optional[str] = None
104
+ azure_resource_name: Optional[str] = None
105
+
106
+ def __post_init__(self):
107
+ super().__post_init__()
108
+ self.provider_endpoint = f"{self.azure_resource_name}.openai.azure.com"
109
+
110
+
111
+ @dataclass
112
+ class OpenAIProvider(Provider):
113
+ """
114
+ OpenAI specific attributes
115
+ """
116
+
117
+ provider_name: str = OPENAI
118
+ provider_endpoint: Optional[str] = "api.openai.com"
119
+
120
+
121
+ @dataclass
122
+ class OCIGenAIProvider(Provider):
123
+ """
124
+ OCI Gen AI specific attributes
125
+
126
+ :param str oci_apiformat: Specifies the format in which the API expects
127
+ data to be sent and received. Supported values are 'COHERE' and 'GENERIC'
128
+ :param str oci_compartment_id: Specifies the OCID of the compartment you
129
+ are permitted to access when calling the OCI Generative AI service
130
+ :param str oci_endpoint_id: This attributes indicates the endpoint OCID
131
+ of the Oracle dedicated AI hosting cluster
132
+ :param str oci_runtimetype: This attribute indicates the runtime type of
133
+ the provided model. The supported values are 'COHERE' and 'LLAMA'
134
+ """
135
+
136
+ provider_name: str = OCI
137
+ oci_apiformat: Optional[str] = None
138
+ oci_compartment_id: Optional[str] = None
139
+ oci_endpoint_id: Optional[str] = None
140
+ oci_runtimetype: Optional[str] = None
141
+
142
+
143
+ @dataclass
144
+ class CohereProvider(Provider):
145
+ """
146
+ Cohere AI specific attributes
147
+ """
148
+
149
+ provider_name: str = COHERE
150
+ provider_endpoint = "api.cohere.ai"
151
+
152
+
153
+ @dataclass
154
+ class GoogleProvider(Provider):
155
+ """
156
+ Google AI specific attributes
157
+ """
158
+
159
+ provider_name: str = GOOGLE
160
+ provider_endpoint = "generativelanguage.googleapis.com"
161
+
162
+
163
+ @dataclass
164
+ class HuggingFaceProvider(Provider):
165
+ """
166
+ HuggingFace specific attributes
167
+ """
168
+
169
+ provider_name: str = HUGGINGFACE
170
+ provider_endpoint = "api-inference.huggingface.co"
171
+
172
+
173
+ @dataclass
174
+ class AWSProvider(Provider):
175
+ """
176
+ AWS specific attributes
177
+ """
178
+
179
+ provider_name: str = AWS
180
+ aws_apiformat: Optional[str] = None
181
+
182
+ def __post_init__(self):
183
+ super().__post_init__()
184
+ self.provider_endpoint = f"bedrock-runtime.{self.region}.amazonaws.com"
185
+
186
+
187
+ @dataclass
188
+ class AnthropicProvider(Provider):
189
+ """
190
+ Anthropic specific attributes
191
+ """
192
+
193
+ provider_name: str = ANTHROPIC
194
+ provider_endpoint = "api.anthropic.com"
195
+
196
+
197
+ async def async_enable_provider(
198
+ users: Union[str, List[str]], provider_endpoint: str = None
199
+ ):
200
+ """
201
+ Async API to enable AI profile for database users.
202
+
203
+ This method grants execute privilege on the packages DBMS_CLOUD,
204
+ DBMS_CLOUD_AI and DBMS_CLOUD_PIPELINE. It also enables the database
205
+ user to invoke the AI Provider (LLM) endpoint
206
+
207
+ """
208
+ if isinstance(users, str):
209
+ users = [users]
210
+
211
+ async with async_cursor() as cr:
212
+ for user in users:
213
+ await cr.execute(GRANT_PRIVILEGES_TO_USER.format(user))
214
+ if provider_endpoint:
215
+ await cr.execute(
216
+ ENABLE_AI_PROFILE_DOMAIN_FOR_USER,
217
+ user=user,
218
+ host=provider_endpoint,
219
+ )
220
+
221
+
222
+ async def async_disable_provider(
223
+ users: Union[str, List[str]], provider_endpoint: str = None
224
+ ):
225
+ """
226
+ Async API to disable AI profile for database users
227
+
228
+ Disables AI provider for the user. This method revokes execute privilege
229
+ on the packages DBMS_CLOUD, DBMS_CLOUD_AI and DBMS_CLOUD_PIPELINE. It
230
+ also disables the user to invoke the AI Provider (LLM) endpoint
231
+ """
232
+ if isinstance(users, str):
233
+ users = [users]
234
+
235
+ async with async_cursor() as cr:
236
+ for user in users:
237
+ await cr.execute(REVOKE_PRIVILEGES_FROM_USER.format(user))
238
+ if provider_endpoint:
239
+ await cr.execute(
240
+ DISABLE_AI_PROFILE_DOMAIN_FOR_USER,
241
+ user=user,
242
+ host=provider_endpoint,
243
+ )
244
+
245
+
246
+ def enable_provider(
247
+ users: Union[str, List[str]], provider_endpoint: str = None
248
+ ):
249
+ """
250
+ Enables AI profile for the user. This method grants execute privilege
251
+ on the packages DBMS_CLOUD, DBMS_CLOUD_AI and DBMS_CLOUD_PIPELINE. It
252
+ also enables the user to invoke the AI Provider (LLM) endpoint
253
+ """
254
+ if isinstance(users, str):
255
+ users = [users]
256
+
257
+ with cursor() as cr:
258
+ for user in users:
259
+ cr.execute(GRANT_PRIVILEGES_TO_USER.format(user))
260
+ if provider_endpoint:
261
+ cr.execute(
262
+ ENABLE_AI_PROFILE_DOMAIN_FOR_USER,
263
+ user=user,
264
+ host=provider_endpoint,
265
+ )
266
+
267
+
268
+ def disable_provider(
269
+ users: Union[str, List[str]], provider_endpoint: str = None
270
+ ):
271
+ """
272
+ Disables AI provider for the user. This method revokes execute privilege
273
+ on the packages DBMS_CLOUD, DBMS_CLOUD_AI and DBMS_CLOUD_PIPELINE. It
274
+ also disables the user to invoke the AI(LLM) endpoint
275
+
276
+ """
277
+ if isinstance(users, str):
278
+ users = [users]
279
+
280
+ with cursor() as cr:
281
+ for user in users:
282
+ cr.execute(REVOKE_PRIVILEGES_FROM_USER.format(user))
283
+ if provider_endpoint:
284
+ cr.execute(
285
+ DISABLE_AI_PROFILE_DOMAIN_FOR_USER,
286
+ user=user,
287
+ host=provider_endpoint,
288
+ )
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()