33import logging
44import time
55import os
6+ import requests
67from collections import defaultdict
78from openai import OpenAI
89from tenacity import retry , stop_after_attempt , wait_exponential
2122
2223client = OpenAI (api_key = api_key )
2324
25+ # OMI App credentials for notifications
26+ omi_app_id = os .getenv ('HEY_OMI_APP_ID' )
27+ omi_app_secret = os .getenv ('HEY_OMI_APP_SECRET' )
28+
29+ if not omi_app_id or not omi_app_secret :
30+ raise ValueError ("HEY_OMI_APP_ID and HEY_OMI_APP_SECRET environment variables are required" )
31+
32+ print (f"OMI App ID loaded: { omi_app_id } " )
33+
2434router = APIRouter (prefix = "/notifications" , tags = ["notifications" ])
2535
2636# Set up logging
3141TRIGGER_PHRASES = ["hey omi" , "hey, omi" ] # Base triggers
3242PARTIAL_FIRST = ["hey" , "hey," ] # First part of trigger
3343PARTIAL_SECOND = ["omi" ] # Second part of trigger
34- QUESTION_AGGREGATION_TIME = 5 # seconds to wait for collecting the question
44+ QUESTION_AGGREGATION_TIME = 10 # seconds to wait for collecting the question
3545
3646# Replace the message buffer with a class to better manage state
3747class MessageBuffer :
@@ -81,7 +91,7 @@ def cleanup_old_sessions(self):
8191
8292# Add cooldown tracking
8393notification_cooldowns = defaultdict (float )
84- NOTIFICATION_COOLDOWN = 10 # 10 seconds cooldown between notifications for each session
94+ NOTIFICATION_COOLDOWN = 15 # 15 seconds cooldown between notifications for each session
8595
8696# Add these near the top of the file, after the imports
8797if os .getenv ('HTTPS_PROXY' ):
@@ -101,7 +111,7 @@ def get_openai_response(text):
101111 """Get response from OpenAI for the user's question"""
102112 try :
103113 logger .info (f"Sending question to OpenAI: { text } " )
104-
114+
105115 response = client .chat .completions .create (
106116 model = "gpt-4" ,
107117 messages = [
@@ -112,21 +122,46 @@ def get_openai_response(text):
112122 max_tokens = 150 ,
113123 timeout = 30
114124 )
115-
125+
116126 answer = response .choices [0 ].message .content .strip ()
117127 logger .info (f"Received response from OpenAI: { answer } " )
118128 return answer
119129 except Exception as e :
120130 logger .error (f"Error getting OpenAI response: { str (e )} " )
121131 return "I'm sorry, I encountered an error processing your request."
122132
133+
134+ def send_omi_notification (uid : str , message : str ):
135+ """Send notification using OMI's notifications endpoint"""
136+ try :
137+ url = f"https://api.omi.me/v2/integrations/{ omi_app_id } /notification"
138+ headers = {
139+ "Authorization" : f"Bearer { omi_app_secret } " ,
140+ "Content-Type" : "application/json"
141+ }
142+ params = {
143+ "uid" : uid ,
144+ "message" : message
145+ }
146+
147+ logger .info (f"Sending notification to OMI for uid { uid } : { message } " )
148+
149+ response = requests .post (url , headers = headers , params = params , timeout = 30 )
150+ response .raise_for_status ()
151+
152+ logger .info (f"Successfully sent notification to OMI for uid { uid } " )
153+ return True
154+ except Exception as e :
155+ logger .error (f"Error sending notification to OMI: { str (e )} " )
156+ return False
157+
123158@router .post ('/webhook' )
124159async def webhook (request : WebhookRequest ):
125160 logger .info ("Received webhook POST request" )
126161 logger .info (f"Received data: { request .dict ()} " )
127162
128163 session_id = request .session_id
129- uid = request .uid
164+ uid = request .uid or session_id # Use session_id as uid if uid is not provided
130165 logger .info (f"Processing request for session_id: { session_id } , uid: { uid } " )
131166
132167 if not session_id :
@@ -141,12 +176,18 @@ async def webhook(request: WebhookRequest):
141176 # Add debug logging
142177 logger .debug (f"Current buffer state for session { session_id } : { buffer_data } " )
143178
179+ # Check and handle cooldown
180+ last_notification_time = notification_cooldowns .get (session_id , 0 )
181+ time_since_last_notification = current_time - last_notification_time
182+
183+ # If cooldown has expired, reset it
184+ if time_since_last_notification >= NOTIFICATION_COOLDOWN :
185+ notification_cooldowns [session_id ] = 0
186+
144187 # Only check cooldown if we have a trigger and are about to process
145- if buffer_data ['trigger_detected' ] and not buffer_data ['response_sent' ]:
146- time_since_last_notification = current_time - notification_cooldowns [session_id ]
147- if time_since_last_notification < NOTIFICATION_COOLDOWN :
148- logger .info (f"Cooldown active. { NOTIFICATION_COOLDOWN - time_since_last_notification :.0f} s remaining" )
149- return WebhookResponse (status = "success" )
188+ if buffer_data ['trigger_detected' ] and not buffer_data ['response_sent' ] and time_since_last_notification < NOTIFICATION_COOLDOWN :
189+ logger .info (f"Cooldown active. { NOTIFICATION_COOLDOWN - time_since_last_notification :.0f} s remaining" )
190+ return WebhookResponse (status = "success" )
150191
151192 # Process each segment
152193 for segment in segments :
@@ -164,7 +205,7 @@ async def webhook(request: WebhookRequest):
164205 buffer_data ['collected_question' ] = []
165206 buffer_data ['response_sent' ] = False
166207 buffer_data ['partial_trigger' ] = False
167- notification_cooldowns [ session_id ] = current_time # Set cooldown when trigger is detected
208+ # Note: cooldown is now set when notification is actually sent, not when trigger is detected
168209
169210 # Extract any question part that comes after the trigger
170211 question_part = text .split ('omi,' )[- 1 ].strip () if 'omi,' in text .lower () else ''
@@ -222,24 +263,37 @@ async def webhook(request: WebhookRequest):
222263 )
223264
224265 if should_process and buffer_data ['collected_question' ]:
225- # Process question and send response
266+ # Process question and send notification
226267 full_question = ' ' .join (buffer_data ['collected_question' ]).strip ()
227268 if not full_question .endswith ('?' ):
228269 full_question += '?'
229-
270+
230271 logger .info (f"Processing complete question: { full_question } " )
231272 response = get_openai_response (full_question )
232273 logger .info (f"Got response from OpenAI: { response } " )
233-
274+
275+ # Send notification using OMI endpoint
276+ if uid :
277+ notification_success = send_omi_notification (uid , response )
278+ if notification_success :
279+ logger .info (f"Successfully sent notification for session { session_id } " )
280+ # Set cooldown timestamp when notification is successfully sent
281+ notification_cooldowns [session_id ] = current_time
282+ else :
283+ logger .error (f"Failed to send notification for session { session_id } " )
284+ else :
285+ logger .error (f"No uid provided for session { session_id } , cannot send notification" )
286+
234287 # Reset all states
235288 buffer_data ['trigger_detected' ] = False
236289 buffer_data ['trigger_time' ] = 0
237290 buffer_data ['collected_question' ] = []
238291 buffer_data ['response_sent' ] = True
239292 buffer_data ['partial_trigger' ] = False
240293 has_processed = True
241-
242- return WebhookResponse (status = "success" , message = response )
294+
295+ # Return success without message (notification sent separately)
296+ return WebhookResponse (status = "success" )
243297
244298 # Return success if no response needed
245299 return WebhookResponse (status = "success" )
0 commit comments