select-ai 1.0.0.dev4__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/__init__.py +52 -0
- select_ai/_abc.py +74 -0
- select_ai/_enums.py +14 -0
- select_ai/action.py +21 -0
- select_ai/admin.py +108 -0
- select_ai/async_profile.py +468 -0
- select_ai/base_profile.py +166 -0
- select_ai/conversation.py +249 -0
- select_ai/db.py +171 -0
- select_ai/errors.py +49 -0
- select_ai/profile.py +397 -0
- select_ai/provider.py +187 -0
- select_ai/sql.py +105 -0
- select_ai/synthetic_data.py +84 -0
- select_ai/vector_index.py +542 -0
- select_ai/version.py +8 -0
- select_ai-1.0.0.dev4.dist-info/METADATA +25 -0
- select_ai-1.0.0.dev4.dist-info/RECORD +21 -0
- select_ai-1.0.0.dev4.dist-info/WHEEL +5 -0
- select_ai-1.0.0.dev4.dist-info/licenses/LICENSE.txt +35 -0
- select_ai-1.0.0.dev4.dist-info/top_level.txt +1 -0
select_ai/profile.py
ADDED
|
@@ -0,0 +1,397 @@
|
|
|
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 contextlib import contextmanager
|
|
10
|
+
from dataclasses import replace as dataclass_replace
|
|
11
|
+
from typing import Iterator, Mapping, Optional, Union
|
|
12
|
+
|
|
13
|
+
import oracledb
|
|
14
|
+
import pandas
|
|
15
|
+
|
|
16
|
+
from select_ai import Conversation
|
|
17
|
+
from select_ai.action import Action
|
|
18
|
+
from select_ai.base_profile import BaseProfile, ProfileAttributes
|
|
19
|
+
from select_ai.db import cursor
|
|
20
|
+
from select_ai.errors import ProfileNotFoundError
|
|
21
|
+
from select_ai.provider import Provider
|
|
22
|
+
from select_ai.sql import (
|
|
23
|
+
GET_USER_AI_PROFILE_ATTRIBUTES,
|
|
24
|
+
LIST_USER_AI_PROFILES,
|
|
25
|
+
)
|
|
26
|
+
from select_ai.synthetic_data import SyntheticDataAttributes
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class Profile(BaseProfile):
|
|
30
|
+
"""Profile class represents an AI Profile. It defines
|
|
31
|
+
attributes and methods to interact with the underlying
|
|
32
|
+
AI Provider. All methods in this class are synchronous
|
|
33
|
+
or blocking
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self, *args, **kwargs):
|
|
37
|
+
super().__init__(*args, **kwargs)
|
|
38
|
+
self._init_profile()
|
|
39
|
+
|
|
40
|
+
def _init_profile(self) -> None:
|
|
41
|
+
"""Initializes AI profile based on the passed attributes
|
|
42
|
+
|
|
43
|
+
:return: None
|
|
44
|
+
:raises: oracledb.DatabaseError
|
|
45
|
+
"""
|
|
46
|
+
if self.profile_name is not None:
|
|
47
|
+
profile_exists = False
|
|
48
|
+
try:
|
|
49
|
+
saved_attributes = self._get_attributes(
|
|
50
|
+
profile_name=self.profile_name
|
|
51
|
+
)
|
|
52
|
+
profile_exists = True
|
|
53
|
+
except ProfileNotFoundError:
|
|
54
|
+
if self.attributes is None:
|
|
55
|
+
raise
|
|
56
|
+
else:
|
|
57
|
+
if self.attributes is None:
|
|
58
|
+
self.attributes = saved_attributes
|
|
59
|
+
if self.merge:
|
|
60
|
+
self.replace = True
|
|
61
|
+
if self.attributes is not None:
|
|
62
|
+
self.attributes = dataclass_replace(
|
|
63
|
+
saved_attributes,
|
|
64
|
+
**self.attributes.dict(exclude_null=True),
|
|
65
|
+
)
|
|
66
|
+
if self.replace or not profile_exists:
|
|
67
|
+
self.create(replace=self.replace)
|
|
68
|
+
|
|
69
|
+
@staticmethod
|
|
70
|
+
def _get_attributes(profile_name) -> ProfileAttributes:
|
|
71
|
+
"""Get AI profile attributes from the Database
|
|
72
|
+
|
|
73
|
+
:param str profile_name: Name of the profile
|
|
74
|
+
:return: select_ai.ProfileAttributes
|
|
75
|
+
:raises: ProfileNotFoundError
|
|
76
|
+
"""
|
|
77
|
+
with cursor() as cr:
|
|
78
|
+
cr.execute(
|
|
79
|
+
GET_USER_AI_PROFILE_ATTRIBUTES,
|
|
80
|
+
profile_name=profile_name.upper(),
|
|
81
|
+
)
|
|
82
|
+
attributes = cr.fetchall()
|
|
83
|
+
if attributes:
|
|
84
|
+
return ProfileAttributes.create(**dict(attributes))
|
|
85
|
+
else:
|
|
86
|
+
raise ProfileNotFoundError(profile_name=profile_name)
|
|
87
|
+
|
|
88
|
+
def get_attributes(self) -> ProfileAttributes:
|
|
89
|
+
"""Get AI profile attributes from the Database
|
|
90
|
+
|
|
91
|
+
:return: select_ai.ProfileAttributes
|
|
92
|
+
"""
|
|
93
|
+
return self._get_attributes(profile_name=self.profile_name)
|
|
94
|
+
|
|
95
|
+
def _set_attribute(
|
|
96
|
+
self,
|
|
97
|
+
attribute_name: str,
|
|
98
|
+
attribute_value: Union[bool, str, int, float],
|
|
99
|
+
):
|
|
100
|
+
parameters = {
|
|
101
|
+
"profile_name": self.profile_name,
|
|
102
|
+
"attribute_name": attribute_name,
|
|
103
|
+
"attribute_value": attribute_value,
|
|
104
|
+
}
|
|
105
|
+
with cursor() as cr:
|
|
106
|
+
cr.callproc(
|
|
107
|
+
"DBMS_CLOUD_AI.SET_ATTRIBUTE", keyword_parameters=parameters
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
def set_attribute(
|
|
111
|
+
self,
|
|
112
|
+
attribute_name: str,
|
|
113
|
+
attribute_value: Union[bool, str, int, float, Provider],
|
|
114
|
+
):
|
|
115
|
+
"""Updates AI profile attribute on the Python object and also
|
|
116
|
+
saves it in the database
|
|
117
|
+
|
|
118
|
+
:param str attribute_name: Name of the AI profile attribute
|
|
119
|
+
:param Union[bool, str, int, float, Provider] attribute_value: Value of
|
|
120
|
+
the profile attribute
|
|
121
|
+
:return: None
|
|
122
|
+
|
|
123
|
+
"""
|
|
124
|
+
self.attributes.set_attribute(attribute_name, attribute_value)
|
|
125
|
+
if isinstance(attribute_value, Provider):
|
|
126
|
+
for k, v in attribute_value.dict().items():
|
|
127
|
+
self._set_attribute(k, v)
|
|
128
|
+
else:
|
|
129
|
+
self._set_attribute(attribute_name, attribute_value)
|
|
130
|
+
|
|
131
|
+
def set_attributes(self, attributes: ProfileAttributes):
|
|
132
|
+
"""Updates AI profile attributes on the Python object and also
|
|
133
|
+
saves it in the database
|
|
134
|
+
|
|
135
|
+
:param ProviderAttributes attributes: Object specifying AI profile
|
|
136
|
+
attributes
|
|
137
|
+
:return: None
|
|
138
|
+
"""
|
|
139
|
+
self.attributes = attributes
|
|
140
|
+
parameters = {
|
|
141
|
+
"profile_name": self.profile_name,
|
|
142
|
+
"attributes": self.attributes.json(),
|
|
143
|
+
}
|
|
144
|
+
with cursor() as cr:
|
|
145
|
+
cr.callproc(
|
|
146
|
+
"DBMS_CLOUD_AI.SET_ATTRIBUTES", keyword_parameters=parameters
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
def create(self, replace: Optional[int] = False) -> None:
|
|
150
|
+
"""Create an AI Profile in the Database
|
|
151
|
+
|
|
152
|
+
:param bool replace: Set True to replace else False
|
|
153
|
+
:return: None
|
|
154
|
+
:raises: oracledb.DatabaseError
|
|
155
|
+
"""
|
|
156
|
+
|
|
157
|
+
parameters = {
|
|
158
|
+
"profile_name": self.profile_name,
|
|
159
|
+
"attributes": self.attributes.json(),
|
|
160
|
+
}
|
|
161
|
+
if self.description:
|
|
162
|
+
parameters["description"] = self.description
|
|
163
|
+
|
|
164
|
+
with cursor() as cr:
|
|
165
|
+
try:
|
|
166
|
+
cr.callproc(
|
|
167
|
+
"DBMS_CLOUD_AI.CREATE_PROFILE",
|
|
168
|
+
keyword_parameters=parameters,
|
|
169
|
+
)
|
|
170
|
+
except oracledb.DatabaseError as e:
|
|
171
|
+
(error,) = e.args
|
|
172
|
+
# If already exists and replace is True then drop and recreate
|
|
173
|
+
if "already exists" in error.message.lower() and replace:
|
|
174
|
+
self.delete(force=True)
|
|
175
|
+
cr.callproc(
|
|
176
|
+
"DBMS_CLOUD_AI.CREATE_PROFILE",
|
|
177
|
+
keyword_parameters=parameters,
|
|
178
|
+
)
|
|
179
|
+
else:
|
|
180
|
+
raise
|
|
181
|
+
|
|
182
|
+
def delete(self, force=False) -> None:
|
|
183
|
+
"""Deletes an AI profile from the database
|
|
184
|
+
|
|
185
|
+
:param bool force: Ignores errors if AI profile does not exist.
|
|
186
|
+
:return: None
|
|
187
|
+
:raises: oracledb.DatabaseError
|
|
188
|
+
"""
|
|
189
|
+
with cursor() as cr:
|
|
190
|
+
cr.callproc(
|
|
191
|
+
"DBMS_CLOUD_AI.DROP_PROFILE",
|
|
192
|
+
keyword_parameters={
|
|
193
|
+
"profile_name": self.profile_name,
|
|
194
|
+
"force": force,
|
|
195
|
+
},
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
@classmethod
|
|
199
|
+
def _from_db(cls, profile_name: str) -> "Profile":
|
|
200
|
+
"""Create a Profile object from attributes saved in the database
|
|
201
|
+
|
|
202
|
+
:param str profile_name:
|
|
203
|
+
:return: select_ai.Profile
|
|
204
|
+
:raises: ProfileNotFoundError
|
|
205
|
+
"""
|
|
206
|
+
with cursor() as cr:
|
|
207
|
+
cr.execute(
|
|
208
|
+
GET_USER_AI_PROFILE_ATTRIBUTES, profile_name=profile_name
|
|
209
|
+
)
|
|
210
|
+
attributes = cr.fetchall()
|
|
211
|
+
if attributes:
|
|
212
|
+
attributes = ProfileAttributes.create(**dict(attributes))
|
|
213
|
+
return cls(profile_name=profile_name, attributes=attributes)
|
|
214
|
+
else:
|
|
215
|
+
raise ProfileNotFoundError(profile_name=profile_name)
|
|
216
|
+
|
|
217
|
+
@classmethod
|
|
218
|
+
def list(cls, profile_name_pattern: str) -> Iterator["Profile"]:
|
|
219
|
+
"""List AI Profiles saved in the database.
|
|
220
|
+
|
|
221
|
+
:param str profile_name_pattern: Regular expressions can be used
|
|
222
|
+
to specify a pattern. Function REGEXP_LIKE is used to perform the
|
|
223
|
+
match
|
|
224
|
+
|
|
225
|
+
:return: Iterator[Profile]
|
|
226
|
+
"""
|
|
227
|
+
with cursor() as cr:
|
|
228
|
+
cr.execute(
|
|
229
|
+
LIST_USER_AI_PROFILES,
|
|
230
|
+
profile_name_pattern=profile_name_pattern,
|
|
231
|
+
)
|
|
232
|
+
for row in cr.fetchall():
|
|
233
|
+
profile_name = row[0]
|
|
234
|
+
description = row[1]
|
|
235
|
+
attributes = cls._get_attributes(profile_name=profile_name)
|
|
236
|
+
yield cls(
|
|
237
|
+
profile_name=profile_name,
|
|
238
|
+
description=description,
|
|
239
|
+
attributes=attributes,
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
def generate(
|
|
243
|
+
self,
|
|
244
|
+
prompt: str,
|
|
245
|
+
action: Optional[Action] = Action.RUNSQL,
|
|
246
|
+
params: Mapping = None,
|
|
247
|
+
) -> Union[pandas.DataFrame, str, None]:
|
|
248
|
+
"""Perform AI translation using this profile
|
|
249
|
+
|
|
250
|
+
:param str prompt: Natural language prompt to translate
|
|
251
|
+
:param select_ai.profile.Action action:
|
|
252
|
+
:param params: Parameters to include in the LLM request. For e.g.
|
|
253
|
+
conversation_id for context-aware chats
|
|
254
|
+
:return: Union[pandas.DataFrame, str]
|
|
255
|
+
"""
|
|
256
|
+
parameters = {
|
|
257
|
+
"prompt": prompt,
|
|
258
|
+
"action": action,
|
|
259
|
+
"profile_name": self.profile_name,
|
|
260
|
+
# "attributes": self.attributes.json(),
|
|
261
|
+
}
|
|
262
|
+
if params:
|
|
263
|
+
parameters["params"] = json.dumps(params)
|
|
264
|
+
with cursor() as cr:
|
|
265
|
+
data = cr.callfunc(
|
|
266
|
+
"DBMS_CLOUD_AI.GENERATE",
|
|
267
|
+
oracledb.DB_TYPE_CLOB,
|
|
268
|
+
keyword_parameters=parameters,
|
|
269
|
+
)
|
|
270
|
+
if data is not None:
|
|
271
|
+
return data.read()
|
|
272
|
+
return None
|
|
273
|
+
|
|
274
|
+
def chat(self, prompt: str, params: Mapping = None) -> str:
|
|
275
|
+
"""Chat with the LLM
|
|
276
|
+
|
|
277
|
+
:param str prompt: Natural language prompt
|
|
278
|
+
:param params: Parameters to include in the LLM request
|
|
279
|
+
:return: str
|
|
280
|
+
"""
|
|
281
|
+
return self.generate(prompt, action=Action.CHAT, params=params)
|
|
282
|
+
|
|
283
|
+
@contextmanager
|
|
284
|
+
def chat_session(self, conversation: Conversation, delete: bool = False):
|
|
285
|
+
"""Starts a new chat session for context-aware conversations
|
|
286
|
+
|
|
287
|
+
:param Conversation conversation: Conversation object to use for this
|
|
288
|
+
chat session
|
|
289
|
+
:param bool delete: Delete conversation after session ends
|
|
290
|
+
|
|
291
|
+
:return:
|
|
292
|
+
"""
|
|
293
|
+
try:
|
|
294
|
+
if (
|
|
295
|
+
conversation.conversation_id is None
|
|
296
|
+
and conversation.attributes is not None
|
|
297
|
+
):
|
|
298
|
+
conversation.create()
|
|
299
|
+
params = {"conversation_id": conversation.conversation_id}
|
|
300
|
+
session = Session(profile=self, params=params)
|
|
301
|
+
yield session
|
|
302
|
+
finally:
|
|
303
|
+
if delete:
|
|
304
|
+
conversation.delete()
|
|
305
|
+
|
|
306
|
+
def narrate(self, prompt: str, params: Mapping = None) -> str:
|
|
307
|
+
"""Narrate the result of the SQL
|
|
308
|
+
|
|
309
|
+
:param str prompt: Natural language prompt
|
|
310
|
+
:param params: Parameters to include in the LLM request
|
|
311
|
+
:return: str
|
|
312
|
+
"""
|
|
313
|
+
return self.generate(prompt, action=Action.NARRATE, params=params)
|
|
314
|
+
|
|
315
|
+
def explain_sql(self, prompt: str, params: Mapping = None) -> str:
|
|
316
|
+
"""Explain the generated SQL
|
|
317
|
+
|
|
318
|
+
:param str prompt: Natural language prompt
|
|
319
|
+
:param params: Parameters to include in the LLM request
|
|
320
|
+
:return: str
|
|
321
|
+
"""
|
|
322
|
+
return self.generate(prompt, action=Action.EXPLAINSQL, params=params)
|
|
323
|
+
|
|
324
|
+
def run_sql(self, prompt: str, params: Mapping = None) -> pandas.DataFrame:
|
|
325
|
+
"""Run the generate SQL statement and return a pandas Dataframe built
|
|
326
|
+
using the result set
|
|
327
|
+
|
|
328
|
+
:param str prompt: Natural language prompt
|
|
329
|
+
:param params: Parameters to include in the LLM request
|
|
330
|
+
:return: pandas.DataFrame
|
|
331
|
+
"""
|
|
332
|
+
data = json.loads(
|
|
333
|
+
self.generate(prompt, action=Action.RUNSQL, params=params)
|
|
334
|
+
)
|
|
335
|
+
return pandas.DataFrame(data)
|
|
336
|
+
|
|
337
|
+
def show_sql(self, prompt: str, params: Mapping = None) -> str:
|
|
338
|
+
"""Show the generated SQL
|
|
339
|
+
|
|
340
|
+
:param str prompt: Natural language prompt
|
|
341
|
+
:param params: Parameters to include in the LLM request
|
|
342
|
+
:return: str
|
|
343
|
+
"""
|
|
344
|
+
return self.generate(prompt, action=Action.SHOWSQL, params=params)
|
|
345
|
+
|
|
346
|
+
def show_prompt(self, prompt: str, params: Mapping = None) -> str:
|
|
347
|
+
"""Show the prompt sent to LLM
|
|
348
|
+
|
|
349
|
+
:param str prompt: Natural language prompt
|
|
350
|
+
:param params: Parameters to include in the LLM request
|
|
351
|
+
:return: str
|
|
352
|
+
"""
|
|
353
|
+
return self.generate(prompt, action=Action.SHOWPROMPT, params=params)
|
|
354
|
+
|
|
355
|
+
def generate_synthetic_data(
|
|
356
|
+
self, synthetic_data_attributes: SyntheticDataAttributes
|
|
357
|
+
):
|
|
358
|
+
"""Generate synthetic data for a single table, multiple tables or a
|
|
359
|
+
full schema.
|
|
360
|
+
|
|
361
|
+
:param select_ai.SyntheticDataAttributes synthetic_data_attributes:
|
|
362
|
+
:return: None
|
|
363
|
+
:raises: oracledb.DatabaseError
|
|
364
|
+
|
|
365
|
+
"""
|
|
366
|
+
keyword_parameters = synthetic_data_attributes.prepare()
|
|
367
|
+
keyword_parameters["profile_name"] = self.profile_name
|
|
368
|
+
with cursor() as cr:
|
|
369
|
+
cr.callproc(
|
|
370
|
+
"DBMS_CLOUD_AI.GENERATE_SYNTHETIC_DATA",
|
|
371
|
+
keyword_parameters=keyword_parameters,
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
class Session:
|
|
376
|
+
"""Session lets you persist request parameters across DBMS_CLOUD_AI
|
|
377
|
+
requests. This is useful in context-aware conversations
|
|
378
|
+
"""
|
|
379
|
+
|
|
380
|
+
def __init__(self, profile: Profile, params: Mapping):
|
|
381
|
+
"""
|
|
382
|
+
|
|
383
|
+
:param profile: An AI Profile to use in this session
|
|
384
|
+
:param params: Parameters to be persisted across requests
|
|
385
|
+
"""
|
|
386
|
+
self.params = params
|
|
387
|
+
self.profile = profile
|
|
388
|
+
|
|
389
|
+
def chat(self, prompt: str):
|
|
390
|
+
# params = {"conversation_id": self.conversation_id}
|
|
391
|
+
return self.profile.chat(prompt=prompt, params=self.params)
|
|
392
|
+
|
|
393
|
+
def __enter__(self):
|
|
394
|
+
return self
|
|
395
|
+
|
|
396
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
397
|
+
pass
|
select_ai/provider.py
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
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, fields
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
from select_ai._abc import SelectAIDataClass
|
|
12
|
+
|
|
13
|
+
OPENAI = "openai"
|
|
14
|
+
COHERE = "cohere"
|
|
15
|
+
AZURE = "azure"
|
|
16
|
+
OCI = "oci"
|
|
17
|
+
GOOGLE = "google"
|
|
18
|
+
ANTHROPIC = "anthropic"
|
|
19
|
+
HUGGINGFACE = "huggingface"
|
|
20
|
+
AWS = "aws"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class Provider(SelectAIDataClass):
|
|
25
|
+
"""
|
|
26
|
+
Base class for AI Provider
|
|
27
|
+
|
|
28
|
+
To create an object of Provider class, use any one of the concrete AI
|
|
29
|
+
provider implementations
|
|
30
|
+
|
|
31
|
+
:param str embedding_model: The embedding model, also known as a
|
|
32
|
+
transformer. Depending on the AI provider, the supported embedding models
|
|
33
|
+
vary
|
|
34
|
+
:param str model: The name of the LLM being used to generate
|
|
35
|
+
responses
|
|
36
|
+
:param str provider_name: The name of the provider being used
|
|
37
|
+
:param str provider_endpoint: Endpoint URL of the AI provider being used
|
|
38
|
+
:param str region: The cloud region of the Gen AI cluster
|
|
39
|
+
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
embedding_model: Optional[str] = None
|
|
43
|
+
model: Optional[str] = None
|
|
44
|
+
provider_name: Optional[str] = None
|
|
45
|
+
provider_endpoint: Optional[str] = None
|
|
46
|
+
region: Optional[str] = None
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
def create(cls, *, provider_name: Optional[str] = None, **kwargs):
|
|
50
|
+
for subclass in cls.__subclasses__():
|
|
51
|
+
if subclass.provider_name == provider_name:
|
|
52
|
+
return subclass(**kwargs)
|
|
53
|
+
return cls(**kwargs)
|
|
54
|
+
|
|
55
|
+
@classmethod
|
|
56
|
+
def key_alias(cls, k):
|
|
57
|
+
return {"provider": "provider_name", "provider_name": "provider"}.get(
|
|
58
|
+
k, k
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
@classmethod
|
|
62
|
+
def keys(cls):
|
|
63
|
+
return {
|
|
64
|
+
"provider",
|
|
65
|
+
"provider_name",
|
|
66
|
+
"embedding_model",
|
|
67
|
+
"model",
|
|
68
|
+
"region",
|
|
69
|
+
"provider_endpoint",
|
|
70
|
+
"azure_deployment_name",
|
|
71
|
+
"azure_embedding_deployment_name",
|
|
72
|
+
"azure_resource_name",
|
|
73
|
+
"oci_apiformat",
|
|
74
|
+
"oci_compartment_id",
|
|
75
|
+
"oci_endpoint_id",
|
|
76
|
+
"oci_runtimetype",
|
|
77
|
+
"aws_apiformat",
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@dataclass
|
|
82
|
+
class AzureProvider(Provider):
|
|
83
|
+
"""
|
|
84
|
+
Azure specific attributes
|
|
85
|
+
|
|
86
|
+
:param str azure_deployment_name: Name of the Azure OpenAI Service
|
|
87
|
+
deployed model.
|
|
88
|
+
:param str azure_embedding_deployment_name: Name of the Azure OpenAI
|
|
89
|
+
deployed embedding model.
|
|
90
|
+
:param str azure_resource_name: Name of the Azure OpenAI Service resource
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
provider_name: str = AZURE
|
|
94
|
+
azure_deployment_name: Optional[str] = None
|
|
95
|
+
azure_embedding_deployment_name: Optional[str] = None
|
|
96
|
+
azure_resource_name: Optional[str] = None
|
|
97
|
+
|
|
98
|
+
def __post_init__(self):
|
|
99
|
+
super().__post_init__()
|
|
100
|
+
self.provider_endpoint = f"{self.azure_resource_name}.openai.azure.com"
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@dataclass
|
|
104
|
+
class OpenAIProvider(Provider):
|
|
105
|
+
"""
|
|
106
|
+
OpenAI specific attributes
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
provider_name: str = OPENAI
|
|
110
|
+
provider_endpoint: Optional[str] = "api.openai.com"
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@dataclass
|
|
114
|
+
class OCIGenAIProvider(Provider):
|
|
115
|
+
"""
|
|
116
|
+
OCI Gen AI specific attributes
|
|
117
|
+
|
|
118
|
+
:param str oci_apiformat: Specifies the format in which the API expects
|
|
119
|
+
data to be sent and received. Supported values are 'COHERE' and 'GENERIC'
|
|
120
|
+
:param str oci_compartment_id: Specifies the OCID of the compartment you
|
|
121
|
+
are permitted to access when calling the OCI Generative AI service
|
|
122
|
+
:param str oci_endpoint_id: This attributes indicates the endpoint OCID
|
|
123
|
+
of the Oracle dedicated AI hosting cluster
|
|
124
|
+
:param str oci_runtimetype: This attribute indicates the runtime type of
|
|
125
|
+
the provided model. The supported values are 'COHERE' and 'LLAMA'
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
provider_name: str = OCI
|
|
129
|
+
oci_apiformat: Optional[str] = None
|
|
130
|
+
oci_compartment_id: Optional[str] = None
|
|
131
|
+
oci_endpoint_id: Optional[str] = None
|
|
132
|
+
oci_runtimetype: Optional[str] = None
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@dataclass
|
|
136
|
+
class CohereProvider(Provider):
|
|
137
|
+
"""
|
|
138
|
+
Cohere AI specific attributes
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
provider_name: str = COHERE
|
|
142
|
+
provider_endpoint = "api.cohere.ai"
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@dataclass
|
|
146
|
+
class GoogleProvider(Provider):
|
|
147
|
+
"""
|
|
148
|
+
Google AI specific attributes
|
|
149
|
+
"""
|
|
150
|
+
|
|
151
|
+
provider_name: str = GOOGLE
|
|
152
|
+
provider_endpoint = "generativelanguage.googleapis.com"
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
@dataclass
|
|
156
|
+
class HuggingFaceProvider(Provider):
|
|
157
|
+
"""
|
|
158
|
+
HuggingFace specific attributes
|
|
159
|
+
"""
|
|
160
|
+
|
|
161
|
+
provider_name: str = HUGGINGFACE
|
|
162
|
+
provider_endpoint = "api-inference.huggingface.co"
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@dataclass
|
|
166
|
+
class AWSProvider(Provider):
|
|
167
|
+
"""
|
|
168
|
+
AWS specific attributes
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
provider_name: str = AWS
|
|
172
|
+
aws_apiformat: Optional[str] = None
|
|
173
|
+
|
|
174
|
+
def __post_init__(self):
|
|
175
|
+
super().__post_init__()
|
|
176
|
+
self.provider_endpoint = f"bedrock-runtime.{self.region}.amazonaws.com"
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
@dataclass
|
|
181
|
+
class AnthropicProvider(Provider):
|
|
182
|
+
"""
|
|
183
|
+
Anthropic specific attributes
|
|
184
|
+
"""
|
|
185
|
+
|
|
186
|
+
provider_name: str = ANTHROPIC
|
|
187
|
+
provider_endpoint = "api.anthropic.com"
|
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 count(*)
|
|
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
|
+
"""
|