3
3
import os
4
4
import json
5
5
import pyaudio
6
- import oracledb
6
+ import requests
7
+ import time
8
+ import wave
7
9
from datetime import datetime
10
+ import oracledb
8
11
import oci
9
12
from oci .config import from_file
10
13
from oci .auth .signers .security_token_signer import SecurityTokenSigner
15
18
)
16
19
from aiohttp import web
17
20
18
- # Global variables to store the latest data
21
+ from oci .ai_speech import AIServiceSpeechClient
22
+ from oci .ai_speech .models import SynthesizeSpeechDetails
23
+
19
24
latest_thetime = None
20
25
latest_question = None
21
26
latest_answer = None
22
27
compartment_id = os .getenv ('COMPARTMENT_ID' )
23
28
print (f"compartment_id: { compartment_id } " )
24
- pw = getpass .getpass ("Enter database user password:" )
25
29
26
- # Use this when making a connection with a wallet
27
30
connection = oracledb .connect (
28
31
user = "moviestream" ,
29
- password = pw ,
32
+ password = "Welcome12345" ,
30
33
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"
33
37
)
34
38
print (f"Successfully connected to Oracle Database Connection: { connection } " )
35
39
36
- # Create a FIFO queue
37
40
queue = asyncio .Queue ()
38
41
39
- # Set audio parameters
40
42
SAMPLE_RATE = 16000
41
43
FORMAT = pyaudio .paInt16
42
44
CHANNELS = 1
43
45
BUFFER_DURATION_MS = 96
44
-
45
- # Calculate the number of frames per buffer
46
46
FRAMES_PER_BUFFER = int (SAMPLE_RATE * BUFFER_DURATION_MS / 1000 )
47
47
48
- # Variables to keep track of results and state
49
48
cummulativeResult = ""
50
49
isSelect = False
51
50
last_result_time = None
52
51
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
-
61
52
def audio_callback (in_data , frame_count , time_info , status ):
62
- # This function will be called by PyAudio when there's new audio data
63
53
queue .put_nowait (in_data )
64
54
return (None , pyaudio .paContinue )
65
55
66
56
p = pyaudio .PyAudio ()
67
57
68
- # Open the stream
69
58
stream = p .open (
70
59
format = FORMAT ,
71
60
channels = CHANNELS ,
@@ -77,14 +66,36 @@ def audio_callback(in_data, frame_count, time_info, status):
77
66
78
67
stream .start_stream ()
79
68
config = from_file ()
80
- isInsertResults = True
69
+ isInsertResults = False
81
70
82
71
async def send_audio (client ):
83
72
while True :
84
73
data = await queue .get ()
85
- # Send it over the websocket
86
74
await client .send_data (data )
87
75
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
+
88
99
class SpeechListener (RealtimeClientListener ):
89
100
def on_result (self , result ):
90
101
global cummulativeResult , isSelect , last_result_time
@@ -93,33 +104,37 @@ def on_result(self, result):
93
104
cummulativeResult += transcription
94
105
print (f"Received final results: { transcription } " )
95
106
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 ()
98
109
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 ()
101
112
isSelect = True
102
113
else :
103
114
cummulativeResult = ""
104
115
last_result_time = asyncio .get_event_loop ().time ()
105
116
else :
106
117
print (f"Received partial results: { result ['transcriptions' ][0 ]['transcription' ]} " )
107
118
108
-
109
119
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 } " )
111
122
112
123
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." )
114
126
115
127
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 } " )
117
130
118
131
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 } " )
120
134
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 } " )
123
138
124
139
async def check_idle ():
125
140
global last_result_time , isSelect
@@ -129,93 +144,111 @@ async def check_idle():
129
144
isSelect = False
130
145
await asyncio .sleep (1 )
131
146
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
134
155
def executeSelectAI ():
135
156
global cummulativeResult , isInsertResults , latest_thetime , latest_question , latest_answer
136
157
print (f"executeSelectAI called cummulative result: { cummulativeResult } " )
137
158
138
- # AI query - todo use openai_gpt4o
139
159
query = """SELECT DBMS_CLOUD_AI.GENERATE(
140
160
prompt => :prompt,
141
161
profile_name => 'openai_gpt35',
142
- action => 'narrate ')
162
+ action => 'chat ')
143
163
FROM dual"""
144
164
145
165
try :
146
166
with connection .cursor () as cursor :
147
- cursor .execute (query , prompt = cummulativeResult )
167
+ cursor .execute (query , { ' prompt' : cummulativeResult } )
148
168
result = cursor .fetchone ()
149
169
if result and isinstance (result [0 ], oracledb .LOB ):
150
170
text_result = result [0 ].read ()
151
- print (text_result )
171
+ print (f"Query result: { text_result } " )
152
172
153
173
latest_thetime = datetime .now ()
154
174
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" )
157
205
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 )
172
206
except Exception as e :
173
207
print (f"An error occurred: { e } " )
174
208
175
- cummulativeResult = ""
176
-
177
209
async def handle_request (request ):
178
210
global latest_thetime , latest_question , latest_answer
179
211
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 ,
181
213
"question" : latest_question ,
182
214
"answer" : latest_answer
183
215
}
184
216
return web .json_response (data )
185
217
186
-
187
218
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 )
191
221
192
222
realtime_speech_parameters = RealtimeParameters ()
193
223
realtime_speech_parameters .language_code = "en-US"
194
224
realtime_speech_parameters .model_domain = (
195
225
realtime_speech_parameters .MODEL_DOMAIN_GENERIC
196
226
)
197
- realtime_speech_parameters .partial_silence_threshold_in_ms = 0
198
227
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
- )
203
228
204
229
realtime_speech_url = "wss://realtime.aiservice.us-phoenix-1.oci.oraclecloud.com"
205
230
client = RealtimeClient (
206
231
config = config ,
207
232
realtime_speech_parameters = realtime_speech_parameters ,
208
233
listener = SpeechListener (),
209
234
service_endpoint = realtime_speech_url ,
210
- signer = authenticator () ,
235
+ signer = None ,
211
236
compartment_id = compartment_id ,
212
237
)
213
238
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
+
215
249
loop .create_task (send_audio (client ))
216
250
loop .create_task (check_idle ())
217
251
218
- # Set up the HTTP server
219
252
app = web .Application ()
220
253
app .router .add_get ('/selectai_data' , handle_request )
221
254
runner = web .AppRunner (app )
0 commit comments