Skip to content

Commit 9c1e07d

Browse files
committed
various cleanup and clarifications
1 parent 716d64f commit 9c1e07d

22 files changed

+87729
-222
lines changed

python-realtimeSTT-NL2SQL-TTS/src/STTSelectAITTS.py renamed to interactive-ai-holograms/python-realtimespeech-selectai/src/variations/AIHoloPython.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,21 @@
2727
compartment_id = os.getenv('COMPARTMENT_ID')
2828
print(f"compartment_id: {compartment_id}")
2929

30+
# connection = oracledb.connect(
31+
# user="user",
32+
# password="userpw",
33+
# dsn="yourdb_high",
34+
# config_dir=r"C:\locationofyourwallet",
35+
# wallet_location=r"C:\locationofyourwallet",
36+
# wallet_password="walletpw"
37+
# )
3038
connection = oracledb.connect(
31-
user="user",
32-
password="userpw",
33-
dsn="yourdb_high",
34-
config_dir=r"C:\locationofyourwallet",
35-
wallet_location=r"C:\locationofyourwallet",
36-
wallet_password="walletpw"
39+
user="moviestream",
40+
password="Welcome12345",
41+
dsn="selectaidb_high",
42+
config_dir="/Users/pparkins/Downloads/Wallet_SelectAIDB",
43+
wallet_location="/Users/pparkins/Downloads/Wallet_SelectAIDB",
44+
wallet_password="Welcome12345"
3745
)
3846
print(f"Successfully connected to Oracle Database Connection: {connection}")
3947

python-realtimeSTT-NL2SQL-TTS/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ located here: https://livelabs.oracle.com/pls/apex/r/dbpm/livelabs/view-workshop
33

44
Quick notes are here...
55
- setup the database side with Select AI configured, etc.
6-
- oci session authenticate ; oci iam region list --config-file ~/.oci/config --profile MYSPEECHAIPROFILE --auth security_token
7-
- $env:COMPARTMENT_ID = "ocid1.compartment.oc1..YOURCOMPARMENTID"
8-
- python src/RealtimeSpeechSelectAI.py
6+
- setup OCI config profile auth (instance or security_token)
7+
- export COMPARTMENT_ID
8+
- python src/RealtimeSTT_NL2SQL_TTS_AudioPlay.py
Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
https://artifactory.oci.oraclecorp.com/ocas-service-platform-dev-pypi-local/oci.ai-speech-realtime/0.2.0/oci.ai_speech_realtime-0.2.0-py2.py3-none-any.whl
2-
https://artifactory.oci.oraclecorp.com/global-dev-pypi/oci-2.129.1+preview.1.1805-py3-none-any.whl
3-
PyAudio>=0.2.14
41
websockets==11.0.3; python_version >= "3.7"
52
websockets==9.1; python_version == "3.6"
6-
aiohttp
7-
oracledb
3+
aiohttp~=3.10.10
4+
oracledb~=2.4.1
85
certifi==2024.8.30
96
cffi==1.17.1
107
circuitbreaker==2.0.0
@@ -14,4 +11,9 @@ pycparser==2.22
1411
pyOpenSSL==24.2.1
1512
python-dateutil==2.9.0.post0
1613
pytz==2024.2
17-
six==1.16.0
14+
six==1.16.0
15+
oci-ai-speech-realtime
16+
oci.ai_speech
17+
18+
requests~=2.32.3
19+
PyAudio~=0.2.14

python-realtimeSTT-NL2SQL-TTS/src/RealtimeSpeechSelectAI.py renamed to python-realtimeSTT-NL2SQL-TTS/src/RealtimeSTT_NL2SQL_TTS_AudioPlayback.py

Lines changed: 105 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
import os
44
import json
55
import pyaudio
6-
import oracledb
6+
import requests
7+
import time
8+
import wave
79
from datetime import datetime
10+
import oracledb
811
import oci
912
from oci.config import from_file
1013
from oci.auth.signers.security_token_signer import SecurityTokenSigner
@@ -15,57 +18,43 @@
1518
)
1619
from aiohttp import web
1720

18-
# Global variables to store the latest data
21+
from oci.ai_speech import AIServiceSpeechClient
22+
from oci.ai_speech.models import SynthesizeSpeechDetails
23+
1924
latest_thetime = None
2025
latest_question = None
2126
latest_answer = None
2227
compartment_id = os.getenv('COMPARTMENT_ID')
2328
print(f"compartment_id: {compartment_id}")
24-
pw = getpass.getpass("Enter database user password:")
2529

26-
# Use this when making a connection with a wallet
2730
connection = oracledb.connect(
2831
user="moviestream",
29-
password=pw,
32+
password="Welcome12345",
3033
dsn="selectaidb_high",
31-
config_dir=r"C:\Users\paulp\Downloads\Wallet_SelectAIDB",
32-
wallet_location=r"C:\Users\paulp\Downloads\Wallet_SelectAIDB"
34+
config_dir="/Users/pparkins/Downloads/Wallet_SelectAIDB",
35+
wallet_location="/Users/pparkins/Downloads/Wallet_SelectAIDB",
36+
wallet_password="Welcome12345"
3337
)
3438
print(f"Successfully connected to Oracle Database Connection: {connection}")
3539

36-
# Create a FIFO queue
3740
queue = asyncio.Queue()
3841

39-
# Set audio parameters
4042
SAMPLE_RATE = 16000
4143
FORMAT = pyaudio.paInt16
4244
CHANNELS = 1
4345
BUFFER_DURATION_MS = 96
44-
45-
# Calculate the number of frames per buffer
4646
FRAMES_PER_BUFFER = int(SAMPLE_RATE * BUFFER_DURATION_MS / 1000)
4747

48-
# Variables to keep track of results and state
4948
cummulativeResult = ""
5049
isSelect = False
5150
last_result_time = None
5251

53-
def authenticator():
54-
config = from_file("~/.oci/config", "MYSPEECHAIPROFILE")
55-
with open(config["security_token_file"], "r") as f:
56-
token = f.readline()
57-
private_key = oci.signer.load_private_key_from_file(config["key_file"])
58-
auth = SecurityTokenSigner(token=token, private_key=private_key)
59-
return auth
60-
6152
def audio_callback(in_data, frame_count, time_info, status):
62-
# This function will be called by PyAudio when there's new audio data
6353
queue.put_nowait(in_data)
6454
return (None, pyaudio.paContinue)
6555

6656
p = pyaudio.PyAudio()
6757

68-
# Open the stream
6958
stream = p.open(
7059
format=FORMAT,
7160
channels=CHANNELS,
@@ -77,14 +66,36 @@ def audio_callback(in_data, frame_count, time_info, status):
7766

7867
stream.start_stream()
7968
config = from_file()
80-
isInsertResults = True
69+
isInsertResults = False
8170

8271
async def send_audio(client):
8372
while True:
8473
data = await queue.get()
85-
# Send it over the websocket
8674
await client.send_data(data)
8775

76+
def play_audio(file_path):
77+
try:
78+
wf = wave.open(file_path, 'rb')
79+
p = pyaudio.PyAudio()
80+
stream = p.open(
81+
format=p.get_format_from_width(wf.getsampwidth()),
82+
channels=wf.getnchannels(),
83+
rate=wf.getframerate(),
84+
output=True
85+
)
86+
87+
data = wf.readframes(1024)
88+
while data:
89+
stream.write(data)
90+
data = wf.readframes(1024)
91+
92+
stream.stop_stream()
93+
stream.close()
94+
p.terminate()
95+
print("Audio playback finished.")
96+
except Exception as e:
97+
print(f"Error playing audio: {e}")
98+
8899
class SpeechListener(RealtimeClientListener):
89100
def on_result(self, result):
90101
global cummulativeResult, isSelect, last_result_time
@@ -93,33 +104,37 @@ def on_result(self, result):
93104
cummulativeResult += transcription
94105
print(f"Received final results: {transcription}")
95106
print(f"Current cummulative result: {cummulativeResult}")
96-
if cummulativeResult.lower().startswith("select ai"):
97-
cummulativeResult = cummulativeResult[len("select ai"):].strip()
107+
if cummulativeResult.lower().startswith("hey db"):
108+
cummulativeResult = cummulativeResult[len("hey db"):].strip()
98109
isSelect = True
99-
elif cummulativeResult.lower().startswith("select the eye"):
100-
cummulativeResult = cummulativeResult[len("select the eye"):].strip()
110+
elif cummulativeResult.lower().startswith("adb"):
111+
cummulativeResult = cummulativeResult[len("adb"):].strip()
101112
isSelect = True
102113
else:
103114
cummulativeResult = ""
104115
last_result_time = asyncio.get_event_loop().time()
105116
else:
106117
print(f"Received partial results: {result['transcriptions'][0]['transcription']}")
107118

108-
109119
def on_ack_message(self, ackmessage):
110-
return super().on_ack_message(ackmessage)
120+
"""Handle acknowledgment messages (required by the abstract class)."""
121+
print(f"ACK received: {ackmessage}")
111122

112123
def on_connect(self):
113-
return super().on_connect()
124+
"""Handle connection event (required by the abstract class)."""
125+
print("Connected to Realtime Speech Service.")
114126

115127
def on_connect_message(self, connectmessage):
116-
return super().on_connect_message(connectmessage)
128+
"""Handle connection messages (required by the abstract class)."""
129+
print(f"Connect message: {connectmessage}")
117130

118131
def on_network_event(self, ackmessage):
119-
return super().on_network_event(ackmessage)
132+
"""Handle network events (required by the abstract class)."""
133+
print(f"Network event: {ackmessage}")
120134

121-
def on_error(self):
122-
return super().on_error()
135+
def on_error(self, exception):
136+
"""Handle errors (required by the abstract class)."""
137+
print(f"An error occurred: {exception}")
123138

124139
async def check_idle():
125140
global last_result_time, isSelect
@@ -129,93 +144,111 @@ async def check_idle():
129144
isSelect = False
130145
await asyncio.sleep(1)
131146

132-
# Function to execute AI query and optionally insert results into the table
133-
# For example Select AI I am looking for the top five selling movies for the latest month please
147+
148+
def authenticator():
149+
config = from_file("~/.oci/config", "MYSPEECHAIPROFILE")
150+
with open(config["security_token_file"], "r") as f:
151+
token = f.readline()
152+
private_key = oci.signer.load_private_key_from_file(config["key_file"])
153+
auth = SecurityTokenSigner(token=token, private_key=private_key)
154+
return auth
134155
def executeSelectAI():
135156
global cummulativeResult, isInsertResults, latest_thetime, latest_question, latest_answer
136157
print(f"executeSelectAI called cummulative result: {cummulativeResult}")
137158

138-
# AI query - todo use openai_gpt4o
139159
query = """SELECT DBMS_CLOUD_AI.GENERATE(
140160
prompt => :prompt,
141161
profile_name => 'openai_gpt35',
142-
action => 'narrate')
162+
action => 'chat')
143163
FROM dual"""
144164

145165
try:
146166
with connection.cursor() as cursor:
147-
cursor.execute(query, prompt=cummulativeResult)
167+
cursor.execute(query, {'prompt': cummulativeResult})
148168
result = cursor.fetchone()
149169
if result and isinstance(result[0], oracledb.LOB):
150170
text_result = result[0].read()
151-
print(text_result)
171+
print(f"Query result: {text_result}")
152172

153173
latest_thetime = datetime.now()
154174
latest_question = cummulativeResult
155-
latest_answer = text_result[:3000] # Truncate if necessary
156-
cummulativeResult = ""
175+
latest_answer = text_result[:3000]
176+
177+
cummulativeResult = ""
178+
179+
# API key-based authentication...
180+
config = oci.config.from_file("~/.oci/config", "DEFAULT")
181+
speech_client = AIServiceSpeechClient(config)
182+
183+
text_to_speech = SynthesizeSpeechDetails(
184+
text=f" {latest_answer}",
185+
is_stream_enabled=False,
186+
configuration=oci.ai_speech.models.TtsOracleConfiguration(
187+
model_family="ORACLE",
188+
# Brian Annabelle Bob Stacy Phil Cindy Brad
189+
model_details=oci.ai_speech.models.TtsOracleTts2NaturalModelDetails(voice_id="Brian"),
190+
speech_settings=oci.ai_speech.models.TtsOracleSpeechSettings(
191+
speech_mark_types=["WORD"]
192+
),
193+
)
194+
)
195+
196+
response = speech_client.synthesize_speech(synthesize_speech_details=text_to_speech)
197+
198+
with open("TTSoutput.wav", "wb") as audio_file:
199+
audio_file.write(response.data.content)
200+
201+
print("Speech synthesis completed and saved as TTSoutput.wav")
202+
203+
# Play the generated speech
204+
play_audio("TTSoutput.wav")
157205

158-
if isInsertResults:
159-
insert_query = """
160-
INSERT INTO selectai_data (thetime, question, answer)
161-
VALUES (:thetime, :question, :answer)
162-
"""
163-
cursor.execute(insert_query, {
164-
'thetime': latest_thetime,
165-
'question': latest_question,
166-
'answer': latest_answer
167-
})
168-
connection.commit()
169-
print("Insert successful.")
170-
else:
171-
print(result)
172206
except Exception as e:
173207
print(f"An error occurred: {e}")
174208

175-
cummulativeResult = ""
176-
177209
async def handle_request(request):
178210
global latest_thetime, latest_question, latest_answer
179211
data = {
180-
"thetime": latest_thetime.isoformat() if latest_thetime else None, # Convert datetime to ISO format
212+
"thetime": latest_thetime.isoformat() if latest_thetime else None,
181213
"question": latest_question,
182214
"answer": latest_answer
183215
}
184216
return web.json_response(data)
185217

186-
187218
if __name__ == "__main__":
188-
# Run the event loop
189-
def message_callback(message):
190-
print(f"Received message: {message}")
219+
loop = asyncio.new_event_loop() # Fix event loop issue
220+
asyncio.set_event_loop(loop)
191221

192222
realtime_speech_parameters = RealtimeParameters()
193223
realtime_speech_parameters.language_code = "en-US"
194224
realtime_speech_parameters.model_domain = (
195225
realtime_speech_parameters.MODEL_DOMAIN_GENERIC
196226
)
197-
realtime_speech_parameters.partial_silence_threshold_in_ms = 0
198227
realtime_speech_parameters.final_silence_threshold_in_ms = 2000
199-
realtime_speech_parameters.should_ignore_invalid_customizations = False
200-
realtime_speech_parameters.stabilize_partial_results = (
201-
realtime_speech_parameters.STABILIZE_PARTIAL_RESULTS_NONE
202-
)
203228

204229
realtime_speech_url = "wss://realtime.aiservice.us-phoenix-1.oci.oraclecloud.com"
205230
client = RealtimeClient(
206231
config=config,
207232
realtime_speech_parameters=realtime_speech_parameters,
208233
listener=SpeechListener(),
209234
service_endpoint=realtime_speech_url,
210-
signer=authenticator(),
235+
signer=None,
211236
compartment_id=compartment_id,
212237
)
213238

214-
loop = asyncio.get_event_loop()
239+
# Instance, resource principal, or session token-based authentication (as shown below) can also be used
240+
# client = AIServiceSpeechClient(
241+
# config=config,
242+
# realtime_speech_parameters=realtime_speech_parameters,
243+
# listener=SpeechListener(),
244+
# service_endpoint=realtime_speech_url,
245+
# signer=authenticator(),
246+
# compartment_id=compartment_id,
247+
# )
248+
215249
loop.create_task(send_audio(client))
216250
loop.create_task(check_idle())
217251

218-
# Set up the HTTP server
219252
app = web.Application()
220253
app.router.add_get('/selectai_data', handle_request)
221254
runner = web.AppRunner(app)

0 commit comments

Comments
 (0)