An AsyncProfile object can be created with select_ai.AsyncProfile().
AsyncProfile supports concurrent programming with asyncio.
Unless explicitly noted as synchronous, the AsyncProfile methods should be
used with await.
Use AsyncProfile in applications that already use
select_ai.async_connect() or select_ai.create_pool_async(). The async
profile object uses the same database profile objects as Profile; only the
Python API style changes.
Because AsyncProfile initializes itself from the database, create or fetch
instances with await:
async_profile = await select_ai.AsyncProfile(
profile_name="async_oci_ai_profile",
)
Before creating an async profile, make sure the database user has the required privileges, a credential for the AI provider, network access to the provider endpoint, and access to the database objects included in the profile. See Privileges, Credential, Provider, and ProfileAttributes.
1. Async profile lifecycle¶
The usual async profile lifecycle is:
Create or reuse an async database connection or async pool.
Create a provider object.
Create
ProfileAttributeswith the provider, credential name, and object list.Create the profile with
await select_ai.AsyncProfile(...).Reuse the profile later by name.
Enable or disable the profile without deleting it.
Update profile attributes when provider settings or object scope changes.
Delete profiles that are no longer needed.
replace=True recreates a profile when a profile with the same name already
exists. merge=True fetches the existing profile and updates it with the
non-null attributes passed by the caller.
2. Async profile actions¶
Method |
Description |
|---|---|
|
Generates SQL for a natural language prompt without executing it. |
|
Generates SQL, executes it, and returns a |
|
Generates SQL, executes it, and returns a natural language answer. |
|
Explains the generated SQL for a prompt. |
|
Shows the prompt sent to the model. |
|
Sends a general chat prompt to the model. |
|
Summarizes inline content or content referenced by a URI. |
|
Translates text from one language to another. |
2.1. AsyncProfile API¶
- class select_ai.AsyncProfile(*args, **kwargs)¶
AsyncProfile defines methods to interact with the underlying AI Provider asynchronously.
- async add_negative_feedback(prompt_spec: Tuple[str, Action] | None = None, sql_id: str | None = None, response: str | None = None, feedback_content: str | None = None)¶
Give negative feedback to the LLM
- Parameters:
prompt_spec (Tuple[str, select_ai.action.Action]) – First element is the prompt; second is the corresponding action
sql_id (str) – SQL identifier from V$MAPPED_SQL view
response (str) – Expected SQL from LLM
feedback_content (str) – Actual feedback in natural language
- async add_positive_feedback(prompt_spec: Tuple[str, Action] | None = None, sql_id: str | None = None)¶
Give positive feedback to the LLM
- Parameters:
prompt_spec (Tuple[str, select_ai.action.Action]) – First element is the prompt; second is the corresponding action
sql_id (str) – SQL identifier from V$MAPPED_SQL view
- async chat(prompt, params: Mapping = None, stream: bool = False, chunk_size: int = 8192, *, attributes: Mapping = None) str | AsyncGenerator[str, None]¶
Asynchronously chat with the LLM
- Parameters:
- Returns:
str
- chat_session(conversation: AsyncConversation, delete: bool = False)¶
Starts a new chat session for context-aware conversations
- Parameters:
conversation (AsyncConversation) – Conversation object to use for this chat session
delete (bool) – Delete conversation after session ends
- async create(replace: int | None = False) None¶
Asynchronously create an AI Profile in the Database
- Parameters:
replace (bool) – Set True to replace else False
- Returns:
None
- Raises:
oracledb.DatabaseError
- async delete(force=False) None¶
Asynchronously deletes an AI profile from the database
- Parameters:
force (bool) – Ignores errors if AI profile does not exist.
- Returns:
None
- Raises:
oracledb.DatabaseError
- async delete_feedback(prompt_spec: Tuple[str, Action] = None, sql_id: str | None = None)¶
Delete feedback from the database
- Parameters:
prompt_spec (Tuple[str, select_ai.action.Action]) – First element is the prompt; second is the corresponding action
sql_id (str) – SQL identifier from V$MAPPED_SQL view
- async classmethod delete_profile(profile_name: str, force: bool = False)¶
Asynchronously deletes an AI profile from the database
- async disable() None¶
Asynchronously disable this AI profile in the database.
- Returns:
None
- Raises:
oracledb.DatabaseError
- async enable() None¶
Asynchronously enable this AI profile in the database.
- Returns:
None
- Raises:
oracledb.DatabaseError
- async explain_sql(prompt: str, params: Mapping = None, stream: bool = False, chunk_size: int = 8192, *, attributes: Mapping = None)¶
Explain the generated SQL
- Parameters:
- Returns:
str
- async classmethod fetch(profile_name: str, owner: str | None = None) AsyncProfile¶
Asynchronously create an AI Profile object from attributes saved in the database
- async generate(prompt: str, action=Action.SHOWSQL, params: Mapping = None, stream: bool = False, chunk_size: int = 8192, *, attributes: Mapping = None) DataFrame | str | AsyncGenerator[str, None] | None¶
Asynchronously perform AI translation using this profile
- Parameters:
prompt (str) – Natural language prompt to translate
action (select_ai.action.Action)
params – Parameters to include in the LLM request. For e.g. conversation_id for context-aware chats
attributes (Mapping) – Profile attributes to override for this request
stream (bool) – Return an async iterator of response chunks
chunk_size (int) – Number of characters to read per stream chunk
- Returns:
Union[pandas.DataFrame, str]
- async generate_synthetic_data(synthetic_data_attributes: SyntheticDataAttributes) None¶
Generate synthetic data for a single table, multiple tables or a full schema.
- Parameters:
synthetic_data_attributes (select_ai.SyntheticDataAttributes)
- Returns:
None
- Raises:
oracledb.DatabaseError
- async get_attributes() ProfileAttributes¶
Asynchronously gets AI profile attributes from the Database
- Returns:
select_ai.ProfileAttributes
- Raises:
ProfileNotFoundError
- async grant_access(user_or_role_name: str) None¶
Asynchronously grant a user or role access to this AI profile.
- classmethod list(profile_name_pattern: str = '.*', owner: str | None = None) AsyncGenerator[AsyncProfile, None]¶
Asynchronously list AI Profiles saved in the database.
- async narrate(prompt, params: Mapping = None, stream: bool = False, chunk_size: int = 8192, *, attributes: Mapping = None) str | AsyncGenerator[str, None]¶
Narrate the result of the SQL
- Parameters:
- Returns:
str
- async revoke_access(user_or_role_name: str) None¶
Asynchronously revoke a user or role’s profile access.
- async run_pipeline(prompt_specifications: List[Tuple[str, Action]], continue_on_error: bool = False, *, attributes: Mapping = None) List[object]¶
Submit prompt/action pairs as a database pipeline
- Parameters:
prompt_specifications (List[Tuple[str, select_ai.action.Action]]) – List of 2-element tuples. First element is the prompt and second is the corresponding action
continue_on_error (bool) – True to continue on error else False
attributes (Mapping) – Profile attributes to override for every request in the pipeline
- Returns:
Ordered list of strings for successful operations and driver error objects for failures when continue_on_error=True. RUNSQL results remain JSON strings; they are not converted to DataFrames.
Operations execute sequentially. Round-trip reduction requires a supporting database version; reading returned CLOBs adds calls. With continue_on_error=False, an operation failure raises an exception.
- async run_sql(prompt, params: Mapping = None, *, attributes: Mapping = None) DataFrame¶
Explain the generated SQL
- Parameters:
prompt (str) – Natural language prompt
params – Parameters to include in the LLM request
attributes (Mapping) – Profile attributes to override for this request
- Returns:
pandas.DataFrame
- async set_attribute(attribute_name: str, attribute_value: bool | str | int | float | Provider)¶
Updates AI profile attribute on the Python object and also saves it in the database
- async set_attributes(attributes: ProfileAttributes)¶
Updates AI profile attributes on the Python object and also saves it in the database
- Parameters:
attributes (ProfileAttributes) – Object specifying AI profile attributes
- Returns:
None
- async show_prompt(prompt: str, params: Mapping = None, stream: bool = False, chunk_size: int = 8192, *, attributes: Mapping = None)¶
Show the prompt sent to LLM
- Parameters:
- Returns:
str
- async show_sql(prompt, params: Mapping = None, stream: bool = False, chunk_size: int = 8192, *, attributes: Mapping = None)¶
Show the generated SQL
- Parameters:
- Returns:
str
- async summarize(content: str = None, prompt: str = None, location_uri: str = None, credential_name: str = None, params: SummaryParams = None) str¶
Generate summary
- Parameters:
prompt (str) – Natural language prompt to guide the summary generation
content (str) – Specifies the text you want to summarize
location_uri (str) – Provides the URI where the text is stored or the path to a local file stored
credential_name (str) – Identifies the credential object used to authenticate with the object store
params (select_ai.summary.SummaryParams) – Parameters to include in the LLM request
2.2. Async Profile creation¶
The following example creates an OCI Gen AI profile that can generate SQL over
objects in the SH schema.
import asyncio
import os
from pprint import pformat
import select_ai
user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")
# This example shows how to asynchronously generate SQLs nad run SQLs
async def main():
await select_ai.async_connect(user=user, password=password, dsn=dsn)
provider = select_ai.OCIGenAIProvider(
region="us-chicago-1", oci_apiformat="GENERIC"
)
profile_attributes = select_ai.ProfileAttributes(
credential_name="my_oci_ai_profile_key",
object_list=[{"owner": "SH"}],
provider=provider,
)
async_profile = await select_ai.AsyncProfile(
profile_name="async_oci_ai_profile",
attributes=profile_attributes,
description="MY OCI AI Profile",
replace=True,
)
print("Created async profile ", async_profile.profile_name)
profile_attributes = await async_profile.get_attributes()
print(
"Profile attributes: ",
pformat(profile_attributes.dict(exclude_null=False)),
)
asyncio.run(main())
output:
Created async profile async_oci_ai_profile
Profile attributes: {'annotations': None,
'case_sensitive_values': None,
'comments': None,
'constraints': None,
'conversation': None,
'credential_name': 'my_oci_ai_profile_key',
'enable_source_offsets': None,
'enable_sources': None,
'enforce_object_list': None,
'max_tokens': '1024',
'object_list': '[{"owner":"SH"}]',
'object_list_mode': None,
'provider': OCIGenAIProvider(embedding_model=None,
model=None,
provider_name='oci',
provider_endpoint=None,
region='us-chicago-1',
oci_apiformat='GENERIC',
oci_compartment_id=None,
oci_endpoint_id=None,
oci_runtimetype=None),
'seed': None,
'stop_tokens': None,
'streaming': None,
'temperature': None,
'vector_index_name': None}
2.3. Reuse Async Profile¶
After a profile has been created, instantiate AsyncProfile with only the
profile name to reuse the database profile:
async_profile = await select_ai.AsyncProfile(
profile_name="async_oci_ai_profile",
)
sql = await async_profile.show_sql(prompt="How many promotions?")
Use AsyncProfile.fetch(...) when you want to create a proxy object from a
saved database profile and raise an error if the profile does not exist:
async_profile = await select_ai.AsyncProfile.fetch(
"async_oci_ai_profile"
)
2.4. Enable and disable AsyncProfile¶
Use await AsyncProfile.disable() to make an existing profile unavailable
without deleting it. Call await AsyncProfile.enable() to make it available
again. These methods change the database profile status and return None.
import asyncio
import os
import select_ai
user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")
profile_name = os.getenv("SELECT_AI_PROFILE_NAME", "oci_ai_profile")
async def main():
await select_ai.async_connect(user=user, password=password, dsn=dsn)
profile = await select_ai.AsyncProfile(profile_name=profile_name)
await profile.disable()
try:
print("Disabled profile:", profile.profile_name)
finally:
await profile.enable()
print("Enabled profile:", profile.profile_name)
asyncio.run(main())
The sample uses SELECT_AI_PROFILE_NAME when set, otherwise it operates on
oci_ai_profile. It always re-enables the profile during cleanup:
output:
Disabled profile: oci_ai_profile
Enabled profile: oci_ai_profile
2.5. Update Async Profile¶
Use set_attribute(...) to update one profile attribute or
set_attributes(...) to update several attributes. Updates are saved to the
database profile.
async_profile = await select_ai.AsyncProfile(
profile_name="async_oci_ai_profile",
)
await async_profile.set_attribute("temperature", 0.1)
await async_profile.set_attributes(
select_ai.ProfileAttributes(
max_tokens=2048,
enforce_object_list=True,
)
)
2.6. Delete Async Profile¶
Use delete(...) or AsyncProfile.delete_profile(...) to remove a profile
from the database. Pass force=True when cleanup should succeed even if the
profile does not exist.
async_profile = await select_ai.AsyncProfile(
profile_name="async_oci_ai_profile",
)
await async_profile.delete(force=True)
await select_ai.AsyncProfile.delete_profile(
"async_oci_ai_profile",
force=True,
)
2.7. Async explain SQL¶
import asyncio
import os
import select_ai
user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")
async def main():
await select_ai.async_connect(user=user, password=password, dsn=dsn)
async_profile = await select_ai.AsyncProfile(
profile_name="async_oci_ai_profile",
)
response = await async_profile.explain_sql("How many promotions ?")
print(response)
asyncio.run(main())
output:
To answer the question "How many promotions", we need to write a SQL query that counts the number of rows in the "PROMOTIONS" table. Here is the query:
```sql
SELECT
COUNT("p"."PROMO_ID") AS "Number of Promotions"
FROM
"SH"."PROMOTIONS" "p";
```
Explanation:
* We use the `COUNT` function to count the number of rows in the table.
* We use the table alias `"p"` to refer to the `"PROMOTIONS"` table.
* We enclose the table name and column name in double quotes to make them case-sensitive.
* We use the `AS` keyword to give an alias to the count column, making it easier to read.
This query will return the total number of promotions in the `"PROMOTIONS"` table.
2.8. Async run SQL¶
import asyncio
import os
import select_ai
user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")
# This example shows how to asynchronously run sql
async def main():
await select_ai.async_connect(user=user, password=password, dsn=dsn)
async_profile = await select_ai.AsyncProfile(
profile_name="async_oci_ai_profile",
)
# run_sql returns a pandas df
df = await async_profile.run_sql("How many promotions?")
print(df)
asyncio.run(main())
output:
PROMOTION_COUNT
0 503
2.9. Async show SQL¶
import asyncio
import os
import select_ai
user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")
async def main():
await select_ai.async_connect(user=user, password=password, dsn=dsn)
async_profile = await select_ai.AsyncProfile(
profile_name="async_oci_ai_profile",
)
response = await async_profile.show_sql("How many promotions?")
print(response)
asyncio.run(main())
output:
SELECT COUNT("p"."PROMO_ID") AS "PROMOTION_COUNT" FROM "SH"."PROMOTIONS" "p"
2.10. Async show prompt¶
Use show_prompt(...) to inspect the prompt that Select AI sends to the
model. This is useful when tuning profile attributes, object lists, comments,
constraints, and provider settings.
async_profile = await select_ai.AsyncProfile(
profile_name="async_oci_ai_profile",
)
prompt = await async_profile.show_prompt(prompt="How many promotions?")
print(prompt)
2.11. Async concurrent SQL¶
import asyncio
import os
import select_ai
user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")
async def main():
select_ai.create_pool_async(
user=user, password=password, dsn=dsn,
min_size=1, max_size=3, increment=1,
)
tasks = []
try:
async_profile = await select_ai.AsyncProfile(
profile_name="async_oci_ai_profile",
)
# Each operation acquires its own connection from the pool.
tasks = [
asyncio.create_task(async_profile.show_sql("How many customers?")),
asyncio.create_task(async_profile.run_sql("How many promotions?")),
asyncio.create_task(async_profile.explain_sql("How many promotions?")),
]
for task in asyncio.as_completed(tasks):
print(await task)
finally:
# Finish cancellation before closing connections, including on errors.
for task in tasks:
if not task.done():
task.cancel()
await asyncio.gather(*tasks, return_exceptions=True)
await select_ai.async_disconnect()
asyncio.run(main())
output:
SELECT COUNT("c"."CUST_ID") AS "customer_count" FROM "SH"."CUSTOMERS" "c"
To answer the question "How many promotions", we need to write a SQL query that counts the number of rows in the "PROMOTIONS" table. Here is the query:
```sql
SELECT
COUNT("p"."PROMO_ID") AS "number_of_promotions"
FROM
"SH"."PROMOTIONS" "p";
```
Explanation:
* We use the `COUNT` function to count the number of rows in the table.
* We use the table alias `"p"` to refer to the `"PROMOTIONS"` table.
* We specify the schema name `"SH"` to ensure that we are accessing the correct table.
* We enclose the table name, schema name, and column name in double quotes to make them case-sensitive.
* The `AS` keyword is used to give an alias to the calculated column, in this case, `"number_of_promotions"`.
This query will return the total number of promotions in the `"PROMOTIONS"` table.
PROMOTION_COUNT
0 503
2.12. Async chat¶
import asyncio
import os
import select_ai
user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")
async def main():
await select_ai.async_connect(user=user, password=password, dsn=dsn)
async_profile = await select_ai.AsyncProfile(
profile_name="async_oci_ai_profile"
)
# Asynchronously send multiple chat prompts
chat_tasks = [
async_profile.chat(prompt="What is OCI ?"),
async_profile.chat(prompt="What is OML4PY?"),
async_profile.chat(prompt="What is Autonomous Database ?"),
]
for chat_task in asyncio.as_completed(chat_tasks):
result = await chat_task
print(result)
asyncio.run(main())
output:
OCI stands for several things depending on the context:
1. **Oracle Cloud Infrastructure (OCI)**: This is a cloud computing service offered by Oracle Corporation. It provides a range of services including computing, storage, networking, database, and more, allowing businesses to build, deploy, and manage applications and services in a secure and scalable manner.
...
..
OML4PY provides a Python interface to OML, allowing users to create, manipulate, and analyze models using Python scripts. It enables users to leverage the power of OML and OMF from within Python, making it easier to integrate modeling and simulation into larger workflows and applications.
...
...
An Autonomous Database is a type of database that uses artificial intelligence (AI) and machine learning (ML) to automate many of the tasks typically performed by a database administrator (DBA)
...
...
2.13. Async streaming chat¶
import asyncio
import os
import select_ai
user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")
async def main():
await select_ai.async_connect(user=user, password=password, dsn=dsn)
async_profile = await select_ai.AsyncProfile(
profile_name="async_oci_ai_profile"
)
chunks = await async_profile.chat(
prompt="What is OCI ?", stream=True, chunk_size=4096
)
async for chunk in chunks:
print(chunk, end="")
print()
asyncio.run(main())
stream=True lets callers consume generated CLOB responses chunk by chunk,
reducing memory pressure and making it easier to progressively forward output
to files, services, or user interfaces. Async streaming text APIs return an
async iterator of str chunks after the awaited method call. The
chunk_size parameter controls the number of CLOB characters read per chunk;
it is not a byte count.
Streaming is supported by generate(), chat(), narrate(),
explain_sql(), show_sql(), and show_prompt(). It is not supported
for run_sql(), which returns a pandas.DataFrame.
The SDK awaits the database function before reading its returned CLOB in
chunks. The first chunk is available after that function returns; this does
not guarantee token delivery while the model is generating. A partially
consumed iterator retains its cursor and connection. Use aclosing() when
iteration can stop early, and consume session streams before leaving the
chat_session() context:
from contextlib import aclosing
chunks = await async_profile.chat("Explain connection pooling.", stream=True)
async with aclosing(chunks):
async for chunk in chunks:
print(chunk, end="")
2.14. Async request-level profile attribute overrides¶
The attributes keyword accepts a mapping of profile attributes to apply to
one async request. These values override the corresponding saved profile
attributes for that request only; they do not update the profile in the
database. The mapping must contain JSON-serializable values.
Request-level attributes are available on the following asynchronous APIs:
AsyncProfile.generate(),chat(), andnarrate().SQL helpers:
explain_sql(),run_sql(),show_sql(), andshow_prompt().AsyncSession.chat(),narrate(),explain_sql(),run_sql(),show_sql(), andshow_prompt().AsyncProfile.run_pipeline(), which applies the same mapping to every prompt/action request in the pipeline.Streaming calls to the text-producing methods, by combining
stream=Truewithattributes=....run_sql()does not support streaming.
The mapping can include attributes such as additional_instructions,
the integer seed, and source_language or target_language. Use
ProfileAttributes for profile-wide defaults; use this mapping when an
override should apply only to the current request.
For translate(), pass language values through its named
source_language and target_language arguments. The attributes
mapping described here applies to the generate/action APIs.
request_attributes = {
"additional_instructions": "Answer in one sentence.",
"seed": 42,
"source_language": "en",
"target_language": "de",
}
response = await async_profile.chat(
prompt="What is Oracle Cloud Infrastructure?",
attributes=request_attributes,
)
For async streaming, await the method call first and then iterate over the returned async iterator. The same mapping can be used with an async session:
chunks = await async_profile.chat(
prompt="Summarize Oracle Cloud Infrastructure.",
stream=True,
attributes=request_attributes,
)
async for chunk in chunks:
print(chunk, end="")
async with async_profile.chat_session(conversation) as session:
response = await session.chat(
prompt="Give one more detail.",
attributes=request_attributes,
)
The following sample uses show_prompt() to verify that the request-only
additional_instructions value reached the generated prompt:
import asyncio
import os
import select_ai
user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")
profile_name = os.getenv("SELECT_AI_PROFILE_NAME", "async_oci_ai_profile")
async def main():
await select_ai.async_connect(user=user, password=password, dsn=dsn)
async_profile = await select_ai.AsyncProfile(profile_name=profile_name)
instruction = "Include the exact marker PYSAI_REQUEST_ATTRIBUTES_SAMPLE."
request_attributes = {
"additional_instructions": instruction,
"seed": 42,
"source_language": "en",
"target_language": "de",
}
prompt = await async_profile.show_prompt(
prompt="Tell me about Oracle Cloud Infrastructure.",
attributes=request_attributes,
)
print("Request attributes applied:", instruction in prompt)
asyncio.run(main())
output:
Request attributes applied: True
2.15. Summarize¶
Summarize inline content
import asyncio
import os
import select_ai
user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")
content = """
A gas cloud in our galaxy, Sagittarius B2, contains enough alcohol to brew 400
trillion pints of beer, and some stars are so cool that you could touch them
without being burned. Meanwhile, on the exoplanet 55 Cancri e, a form of
"hot ice" exists where high pressure prevents water from becoming gas even at
high temperatures. Additionally, some ancient stars found in the Milky Way's
halo are much older than the Sun, providing clues about the early universe and
its composition
"""
async def main():
await select_ai.async_connect(user=user, password=password, dsn=dsn)
async_profile = await select_ai.AsyncProfile(
profile_name="async_oci_ai_profile",
)
summary = await async_profile.summarize(content=content)
print(summary)
asyncio.run(main())
output:
A gas cloud in the Sagittarius B2 galaxy contains a large amount of alcohol,
while some stars are cool enough to touch without being burned. The exoplanet
55 Cancri e has a unique form of "hot ice" where water remains solid despite
high temperatures due to high pressure. Ancient stars in the Milky Way's halo
are older than the Sun, providing insights into the early universe and its composition,
offering clues about the universe's formation and evolution.
Summarize content accessible via a URL
import asyncio
import os
import select_ai
user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")
async def main():
await select_ai.async_connect(user=user, password=password, dsn=dsn)
async_profile = await select_ai.AsyncProfile(
profile_name="async_oci_ai_profile",
)
summary = await async_profile.summarize(
location_uri="https://en.wikipedia.org/wiki/Astronomy"
)
print(summary)
asyncio.run(main())
output:
Astronomy is a natural science that studies celestial objects and phenomena,
using mathematics, physics, and chemistry to explain their origin and evolution.
The field has a long history, with early civilizations making methodical
observations of the night sky, and has since split into observational and
theoretical branches. Observational astronomy focuses on acquiring data
from observations, while theoretical astronomy develops computer or
analytical models to describe astronomical objects and phenomena. The study
of astronomy has led to numerous discoveries, including the existence of
galaxies, the expansion of the universe, and the detection of gravitational
waves. Astronomers use various methods, such as radio, infrared, optical,
ultraviolet, X-ray, and gamma-ray astronomy, to study objects and events in
the universe. The field has also led to the development of new technologies and
has inspired new areas of research, such as astrobiology and the search for
extraterrestrial life. Overall, astronomy is a dynamic and constantly evolving
field that seeks to understand the universe and its many mysteries.
2.16. Translate¶
AsyncProfile.translate() accepts optional source_language and
target_language arguments. Per-call values take precedence over the
profile’s source_language and target_language defaults.
If source_language is omitted for both the call and the profile, source
language detection is delegated to the translation provider. If
target_language is omitted, the profile’s default is used; a target
language must be supplied in one of those two places.
Configure profile-level defaults with ProfileAttributes when creating or
updating a profile:
language_defaults = select_ai.ProfileAttributes(
source_language="en",
target_language="de",
)
await async_profile.set_attributes(language_defaults)
print(await async_profile.translate(text="Thank you"))
When only the target is supplied at the call site, the provider can detect the source language:
print(await async_profile.translate(text="Thank you", target_language="de"))
import asyncio
import os
import select_ai
user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")
profile_name = os.getenv("SELECT_AI_PROFILE_NAME", "async_oci_ai_profile")
async def main():
await select_ai.async_connect(user=user, password=password, dsn=dsn)
async_profile = await select_ai.AsyncProfile(
profile_name=profile_name,
)
response = await async_profile.translate(
text="Thank you",
target_language="de",
)
print(response)
asyncio.run(main())
output:
Danke
2.17. Async pipeline¶
2.17.1. Pipeline compatibility and results¶
run_pipeline() requires python-oracledb>=2.4.0, which provides
create_pipeline() and AsyncConnection.run_pipeline(). If an older
driver lacks these APIs, upgrade it with python -m pip install --upgrade
oracledb. Async operations use Thin mode.
The driver documents true pipelining for Oracle AI Database 26ai and later. On older databases it executes operations individually, without reducing round trips. Pipeline operations execute sequentially, even when true pipelining is available. Select AI returns CLOBs, and reading these adds database calls; do not assume the complete SDK operation uses one round trip. See python-oracledb pipelining.
Results preserve input order. Successful results are strings read from CLOBs.
For Action.RUNSQL, this is the database’s JSON response, rather than the
pandas.DataFrame returned by AsyncProfile.run_sql(). With
continue_on_error=False (the default), an operation error raises an
exception. With continue_on_error=True, failed entries contain driver
error objects; check their type before using them as text:
results = await async_profile.run_pipeline(
[("How many promotions?", select_ai.Action.SHOWSQL)],
continue_on_error=True,
)
for result in results:
if isinstance(result, str):
print(result)
else:
print(f"Pipeline operation failed: {result}")
AsyncProfile.run_pipeline() also accepts attributes=.... The mapping
is applied to every prompt/action request in the pipeline, while the saved
profile remains unchanged.
results = await async_profile.run_pipeline(
prompt_specifications,
attributes={
"additional_instructions": "Keep each answer concise.",
"seed": 42,
},
)
import asyncio
import os
import select_ai
user = os.getenv("SELECT_AI_USER")
password = os.getenv("SELECT_AI_PASSWORD")
dsn = os.getenv("SELECT_AI_DB_CONNECT_STRING")
async def main():
await select_ai.async_connect(user=user, password=password, dsn=dsn)
async_profile = await select_ai.AsyncProfile(
profile_name="async_oci_ai_profile"
)
prompt_specifications = [
("What is Oracle Autonomous Database?", select_ai.Action.CHAT),
("Generate SQL to list all customers?", select_ai.Action.SHOWSQL),
(
"Explain the query: SELECT * FROM sh.products",
select_ai.Action.EXPLAINSQL,
),
("Explain the query: SELECT * FROM sh.products", "INVALID ACTION"),
]
# Operations execute sequentially; round-trip savings depend on the
# database version. Successful results are strings, including RUNSQL JSON.
results = await async_profile.run_pipeline(
prompt_specifications, continue_on_error=True
)
for i, result in enumerate(results):
print(
f"Result {i} for prompt '{prompt_specifications[i][0]}' is: {result}"
)
asyncio.run(main())
output:
Result 0 for prompt 'What is Oracle Autonomous Database?' is: Oracle Autonomous Database is a cloud-based database service that uses artificial intelligence (AI) and machine learning (ML) to automate many of the tasks associated with managing a database. It is a self-driving, self-securing, and self-repairing database that eliminates the need for manual database administration, allowing users to focus on higher-level tasks.
Result 1 for prompt 'Generate SQL to list all customers?' is: SELECT "c"."CUST_ID" AS "Customer ID", "c"."CUST_FIRST_NAME" AS "First Name", "c"."CUST_LAST_NAME" AS "Last Name", "c"."CUST_EMAIL" AS "Email" FROM "SH"."CUSTOMERS" "c"
Result 2 for prompt 'Explain the query: SELECT * FROM sh.products' is: ```sql
SELECT
p.*
FROM
"SH"."PRODUCTS" p;
```
**Explanation:**
This query is designed to retrieve all columns (`*`) from the `"SH"."PRODUCTS"` table.
Here's a breakdown of the query components:
Result 3 for prompt 'Explain the query: SELECT * FROM sh.products' is: ORA-20000: Invalid action - INVALID ACTION
2.19. Give async feedback on generated SQL¶
Use feedback after reviewing the SQL produced for a prompt. Identify the
request with a (prompt, Action) tuple or a sql_id from
V$MAPPED_SQL. The example below assumes an open async connection and an
existing profile over the SH schema:
profile = await select_ai.AsyncProfile.fetch("OCI_AI_PROFILE")
prompt = "How many promotions?"
sql = await profile.show_sql(prompt=prompt)
print(sql)
After inspecting the SQL, record positive feedback if it answers the question:
await profile.add_positive_feedback(
prompt_spec=(prompt, select_ai.Action.SHOWSQL)
)
For an incorrect answer, use add_negative_feedback() with the same request
identifier, response containing the expected SQL, and feedback_content
explaining the correction. Remove obsolete feedback with
delete_feedback() and the same request identifier.
Await these methods when using AsyncProfile.
2.20. List profiles asynchronously¶
Use AsyncProfile.list() to discover saved profiles in the current schema.
Call it on the class; you do not need to create an empty profile first.
Each returned object includes profile_name, owner, and the
owner-qualified qualified_name.
2.20.1. Connect and list your profiles¶
Set SELECT_AI_USER, SELECT_AI_PASSWORD, and
SELECT_AI_DB_CONNECT_STRING before running this complete script. It prints
one qualified name per profile and closes the connection afterward:
import asyncio
import os
import select_ai
async def main():
await select_ai.async_connect(
user=os.environ["SELECT_AI_USER"],
password=os.environ["SELECT_AI_PASSWORD"],
dsn=os.environ["SELECT_AI_DB_CONNECT_STRING"],
)
try:
async for profile in select_ai.AsyncProfile.list():
print(profile.qualified_name)
finally:
await select_ai.async_disconnect()
asyncio.run(main())
For a schema named APP_OWNER containing two profiles, the output could be:
APP_OWNER.OCI_AI_PROFILE
APP_OWNER.OCI_VECTOR_AI_PROFILE
Your results depend on the profiles visible in your schema; result order is not guaranteed. An empty result means no profiles match the requested scope.
2.20.2. Filter by name¶
With a connection open, use profile_name_pattern to match names with a
regular expression. This example lists names starting with OCI_:
async for profile in select_ai.AsyncProfile.list(profile_name_pattern="^OCI_"):
print(profile.qualified_name)
AsyncProfile.list() returns an async iterator. Use async for
directly; do not await the iterator. Put these snippets inside your async
function before disconnecting.