From 906213e62088e51330b74f2f3f7d56aca246759e Mon Sep 17 00:00:00 2001 From: Sergei Date: Tue, 20 Jan 2026 14:41:33 -0800 Subject: [PATCH] Add beneficiary_names_dict support for voice assistant - Voice agent now extracts deploymentId and beneficiaryNamesDict from participant metadata passed via LiveKit token - WellNuoLLM class accepts dynamic deployment_id and beneficiary_names_dict - API calls now include personalized beneficiary names for better responses - Text chat already has this functionality (verified) - Updated LiveKit agent deployed to cloud Also includes: - Speaker toggle button in voice call UI - Keyboard controller integration for chat - Various UI improvements --- app/(tabs)/beneficiaries/[id]/dashboard.tsx | 89 +++++++---- app/(tabs)/chat.tsx | 22 ++- app/_layout.tsx | 17 ++- app/voice-call.tsx | 79 +++++++++- hooks/useLiveKitRoom.ts | 9 +- julia-agent/agent.py | 141 ------------------ julia-agent/julia-ai/pyproject.toml | 1 - julia-agent/julia-ai/src/agent.py | 74 +++++++++- julia-agent/julia-ai/uv.lock | 155 -------------------- julia-agent/requirements.txt | 2 +- package-lock.json | 15 ++ package.json | 1 + services/livekitService.ts | 18 ++- 13 files changed, 273 insertions(+), 350 deletions(-) delete mode 100644 julia-agent/agent.py diff --git a/app/(tabs)/beneficiaries/[id]/dashboard.tsx b/app/(tabs)/beneficiaries/[id]/dashboard.tsx index 22facf7..9ffd570 100644 --- a/app/(tabs)/beneficiaries/[id]/dashboard.tsx +++ b/app/(tabs)/beneficiaries/[id]/dashboard.tsx @@ -9,9 +9,9 @@ import { useBeneficiary } from '@/contexts/BeneficiaryContext'; import { AppColors, BorderRadius, FontSizes, Spacing } from '@/constants/theme'; import { FullScreenError } from '@/components/ui/ErrorMessage'; -// Start with login page, then redirect to dashboard after auth -const LOGIN_URL = 'https://react.eluxnetworks.net/login'; -const DASHBOARD_URL = 'https://react.eluxnetworks.net/dashboard'; +// Use dev.kresoja.net for MobileAppLogin support +// After MobileAppLogin() is called on /login, it auto-redirects to /dashboard +const LOGIN_URL = 'https://dev.kresoja.net/login'; export default function BeneficiaryDashboardScreen() { const { id } = useLocalSearchParams<{ id: string }>(); @@ -24,7 +24,7 @@ export default function BeneficiaryDashboardScreen() { const [userName, setUserName] = useState(null); const [userId, setUserId] = useState(null); const [isTokenLoaded, setIsTokenLoaded] = useState(false); - const [webViewUrl, setWebViewUrl] = useState(DASHBOARD_URL); + const [hasCalledMobileLogin, setHasCalledMobileLogin] = useState(false); const beneficiaryName = currentBeneficiary?.name || 'Dashboard'; @@ -48,31 +48,49 @@ export default function BeneficiaryDashboardScreen() { loadCredentials(); }, []); - // JavaScript to inject token into localStorage before page loads - // Web app uses auth2 key with JSON object: {username, token, user_id} - const injectedJavaScript = authToken - ? ` + // JavaScript to call MobileAppLogin after page loads + // MobileAppLogin sets is_mobile=1, saves auth2, and redirects to /dashboard + // This hides desktop navigation (login/logout/dashboard buttons) + const getMobileLoginScript = () => { + if (!authToken) return ''; + + return ` (function() { try { - // Web app expects auth2 as JSON object with these exact fields - var authData = { - username: '${userName || ''}', - token: '${authToken}', - user_id: ${userId || 'null'} - }; - localStorage.setItem('auth2', JSON.stringify(authData)); - console.log('Auth data injected:', authData.username, 'user_id:', authData.user_id); + // Wait for window.MobileAppLogin to be available + var checkInterval = setInterval(function() { + if (typeof window.MobileAppLogin === 'function') { + clearInterval(checkInterval); + console.log('MobileAppLogin found, calling with auth data...'); + + var authData = { + username: '${userName || ''}', + token: '${authToken}', + user_id: ${userId || 'null'} + }; + + window.MobileAppLogin(authData); + console.log('MobileAppLogin called successfully'); + } + }, 100); + + // Timeout after 5 seconds + setTimeout(function() { + clearInterval(checkInterval); + console.log('MobileAppLogin timeout - function not found'); + }, 5000); } catch(e) { - console.error('Failed to inject token:', e); + console.error('Failed to call MobileAppLogin:', e); } })(); true; - ` - : ''; + `; + }; const handleRefresh = () => { setError(null); setIsLoading(true); + setHasCalledMobileLogin(false); // Reset to call MobileAppLogin again webViewRef.current?.reload(); }; @@ -84,6 +102,21 @@ export default function BeneficiaryDashboardScreen() { const handleNavigationStateChange = (navState: any) => { setCanGoBack(navState.canGoBack); + + // Auto-relogin when session expires (redirected to /login) + // If we're on /login and MobileAppLogin was already called, session expired + const url = navState.url || ''; + const isOnLoginPage = url.includes('/login'); + + if (isOnLoginPage && hasCalledMobileLogin && authToken) { + console.log('[Dashboard] Session expired, re-authenticating...'); + // Reset and call MobileAppLogin again + setHasCalledMobileLogin(false); + setTimeout(() => { + setHasCalledMobileLogin(true); + webViewRef.current?.injectJavaScript(getMobileLoginScript()); + }, 1000); + } }; const handleError = () => { @@ -169,10 +202,20 @@ export default function BeneficiaryDashboardScreen() { setIsLoading(true)} - onLoadEnd={() => setIsLoading(false)} + onLoadEnd={() => { + setIsLoading(false); + // Call MobileAppLogin only once after first load + if (!hasCalledMobileLogin && authToken) { + setHasCalledMobileLogin(true); + // Small delay to ensure React app has mounted + setTimeout(() => { + webViewRef.current?.injectJavaScript(getMobileLoginScript()); + }, 500); + } + }} onError={handleError} onHttpError={handleError} onNavigationStateChange={handleNavigationStateChange} @@ -181,10 +224,6 @@ export default function BeneficiaryDashboardScreen() { startInLoadingState={true} scalesPageToFit={true} allowsBackForwardNavigationGestures={true} - // Inject token into localStorage BEFORE content loads - injectedJavaScriptBeforeContentLoaded={injectedJavaScript} - // Also inject after load in case page reads localStorage late - injectedJavaScript={injectedJavaScript} renderLoading={() => ( diff --git a/app/(tabs)/chat.tsx b/app/(tabs)/chat.tsx index 60de794..6133e98 100644 --- a/app/(tabs)/chat.tsx +++ b/app/(tabs)/chat.tsx @@ -13,12 +13,12 @@ import { FlatList, TextInput, TouchableOpacity, - KeyboardAvoidingView, - Platform, Modal, ActivityIndicator, Keyboard, + Platform, } from 'react-native'; +import { KeyboardAvoidingView } from 'react-native-keyboard-controller'; import { Ionicons } from '@expo/vector-icons'; import { SafeAreaView } from 'react-native-safe-area-context'; import { useRouter } from 'expo-router'; @@ -260,8 +260,18 @@ export default function ChatScreen() { // (same logic as julia-agent/julia-ai/src/agent.py) const normalizedQuestion = normalizeQuestion(trimmedInput); + // Build beneficiary_names_dict from all loaded beneficiaries + // Format: {"21": "papa", "69": "David"} + const beneficiaryNamesDict: Record = {}; + beneficiaries.forEach(b => { + beneficiaryNamesDict[b.id.toString()] = b.name; + }); + + // Get deployment_id from current beneficiary or fallback to first one + const deploymentId = currentBeneficiary?.id?.toString() || beneficiaries[0]?.id?.toString() || '21'; + // Call API with EXACT same params as voice agent - // Using ask_wellnuo_ai instead of voice_ask (same params, same response format) + // Using ask_wellnuo_ai with new beneficiary_names_dict parameter const response = await fetch(API_URL, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, @@ -271,7 +281,8 @@ export default function ChatScreen() { user_name: WELLNUO_USER, token: token, question: normalizedQuestion, - deployment_id: '21', + deployment_id: deploymentId, + beneficiary_names_dict: JSON.stringify(beneficiaryNamesDict), }).toString(), }); @@ -435,8 +446,7 @@ export default function ChatScreen() { {/* Messages */} - - - - - - + + + + + + + + + ); } diff --git a/app/voice-call.tsx b/app/voice-call.tsx index 8e37220..6fbffef 100644 --- a/app/voice-call.tsx +++ b/app/voice-call.tsx @@ -13,20 +13,71 @@ * - Proper cleanup on unmount */ -import React, { useEffect, useRef } from 'react'; +import React, { useEffect, useRef, useState, useMemo } from 'react'; import { View, Text, StyleSheet, TouchableOpacity, Animated, Easing, Dimensions } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { SafeAreaView } from 'react-native-safe-area-context'; import { useRouter } from 'expo-router'; import { AppColors, BorderRadius, FontSizes, Spacing } from '@/constants/theme'; import { useVoiceTranscript } from '@/contexts/VoiceTranscriptContext'; +import { useBeneficiary } from '@/contexts/BeneficiaryContext'; import { useLiveKitRoom, ConnectionState } from '@/hooks/useLiveKitRoom'; +import { setAudioOutput } from '@/utils/audioSession'; +import { api } from '@/services/api'; +import type { Beneficiary } from '@/types'; +import type { BeneficiaryData } from '@/services/livekitService'; const { width: SCREEN_WIDTH } = Dimensions.get('window'); export default function VoiceCallScreen() { const router = useRouter(); const { clearTranscript, addTranscriptEntry } = useVoiceTranscript(); + const { currentBeneficiary } = useBeneficiary(); + + // Speaker toggle state (default: speaker ON) + const [isSpeakerOn, setIsSpeakerOn] = useState(true); + + // Beneficiary state for building beneficiaryData + const [beneficiaries, setBeneficiaries] = useState([]); + + // Load beneficiaries on mount + useEffect(() => { + const loadBeneficiaries = async () => { + try { + const data = await api.getAllBeneficiaries(); + if (data) { + setBeneficiaries(data); + } + } catch (error) { + console.warn('[VoiceCall] Failed to load beneficiaries:', error); + } + }; + loadBeneficiaries(); + }, []); + + // Build beneficiaryData for voice agent + const beneficiaryData = useMemo((): BeneficiaryData | undefined => { + if (beneficiaries.length === 0) { + return undefined; + } + + // Build beneficiary_names_dict from all beneficiaries + // Format: {"21": "papa", "69": "David"} + const beneficiaryNamesDict: Record = {}; + beneficiaries.forEach(b => { + beneficiaryNamesDict[b.id.toString()] = b.name; + }); + + // Get deployment_id from current beneficiary or fallback to first one + const deploymentId = currentBeneficiary?.id?.toString() || beneficiaries[0]?.id?.toString() || '21'; + + console.log('[VoiceCall] BeneficiaryData:', { deploymentId, beneficiaryNamesDict }); + + return { + deploymentId, + beneficiaryNamesDict, + }; + }, [beneficiaries, currentBeneficiary]); // LiveKit hook - ALL logic is here const { @@ -42,6 +93,7 @@ export default function VoiceCallScreen() { toggleMute, } = useLiveKitRoom({ userId: `user-${Date.now()}`, + beneficiaryData, onTranscript: (role, text) => { addTranscriptEntry(role, text); }, @@ -137,6 +189,13 @@ export default function VoiceCallScreen() { router.back(); }; + // Toggle speaker/earpiece + const handleToggleSpeaker = async () => { + const newSpeakerState = !isSpeakerOn; + setIsSpeakerOn(newSpeakerState); + await setAudioOutput(newSpeakerState); + }; + // Format duration as MM:SS const formatDuration = (seconds: number): string => { const mins = Math.floor(seconds / 60); @@ -254,7 +313,7 @@ export default function VoiceCallScreen() { - {/* Bottom controls - centered layout with 2 buttons */} + {/* Bottom controls - centered layout with 3 buttons */} {/* Mute button */} {isMuted ? 'Unmute' : 'Mute'} + {/* Speaker toggle button */} + + + {isSpeakerOn ? 'Speaker' : 'Earpiece'} + + {/* End call button */} @@ -402,7 +475,7 @@ const styles = StyleSheet.create({ alignItems: 'center', paddingVertical: Spacing.xl, paddingHorizontal: Spacing.lg, - gap: 48, // Space between Mute and End Call buttons + gap: 24, // Space between 3 buttons (Mute, Speaker, End Call) }, controlButton: { alignItems: 'center', diff --git a/hooks/useLiveKitRoom.ts b/hooks/useLiveKitRoom.ts index 889a808..8841213 100644 --- a/hooks/useLiveKitRoom.ts +++ b/hooks/useLiveKitRoom.ts @@ -20,7 +20,7 @@ const isIOSSimulator = (): boolean => { return PlatformConstants?.interfaceIdiom === 'simulator' || PlatformConstants?.isSimulator === true; }; -import { getToken, VOICE_NAME } from '@/services/livekitService'; +import { getToken, VOICE_NAME, BeneficiaryData } from '@/services/livekitService'; import { configureAudioForVoiceCall, stopAudioSession, @@ -51,6 +51,7 @@ export interface LogEntry { // Hook options export interface UseLiveKitRoomOptions { userId: string; + beneficiaryData?: BeneficiaryData; onTranscript?: (role: 'user' | 'assistant', text: string) => void; autoConnect?: boolean; } @@ -85,7 +86,7 @@ export interface UseLiveKitRoomReturn { * Main hook for LiveKit voice calls */ export function useLiveKitRoom(options: UseLiveKitRoomOptions): UseLiveKitRoomReturn { - const { userId, onTranscript, autoConnect = false } = options; + const { userId, beneficiaryData, onTranscript, autoConnect = false } = options; // State const [state, setState] = useState('idle'); @@ -248,7 +249,7 @@ export function useLiveKitRoom(options: UseLiveKitRoomOptions): UseLiveKitRoomRe setState('requesting_token'); logInfo('STEP 4/6: Requesting token from server...'); - const tokenResult = await getToken(userId); + const tokenResult = await getToken(userId, beneficiaryData); if (!tokenResult.success || !tokenResult.data) { const errorMsg = tokenResult.error || 'Failed to get token'; @@ -514,7 +515,7 @@ export function useLiveKitRoom(options: UseLiveKitRoomOptions): UseLiveKitRoomRe // Cleanup await stopAudioSession(); } - }, [userId, onTranscript, logInfo, logWarn, logError, logSuccess]); + }, [userId, beneficiaryData, onTranscript, logInfo, logWarn, logError, logSuccess]); // =================== // DISCONNECT FUNCTION diff --git a/julia-agent/agent.py b/julia-agent/agent.py deleted file mode 100644 index 7c49cbc..0000000 --- a/julia-agent/agent.py +++ /dev/null @@ -1,141 +0,0 @@ -""" -WellNuo Voice Agent - Julia AI -LiveKit Agents Cloud deployment -Uses Deepgram STT/TTS + OpenAI GPT-4o LLM -""" - -import os -import json -from dotenv import load_dotenv - -from livekit import agents -from livekit.agents import Agent, AgentSession, RoomEventHandler -from livekit.plugins import deepgram, openai, silero - -load_dotenv(".env.local") - -# Ferdinand data for demo (in production, fetch from API) -FERDINAND_DATA = { - "client": { - "name": "Ferdinand Zmrzli", - "address": "661 Encore Way" - }, - "today_alerts": [ - {"type": "fall_detected", "time": "06:32", "severity": "critical", "location": "bathroom"}, - {"type": "short_sleep", "time": "06:30", "severity": "high", "note": "Only 5 hours sleep (normal: 7-8)"}, - {"type": "missed_medication", "time": "08:30", "severity": "high", "note": "Morning medication not taken"} - ], - "yesterday_alerts": [ - {"type": "high_bathroom_frequency", "time": "15:00", "severity": "medium", "note": "8 visits (normal: 5-6)"} - ], - "summary": { - "total_alerts_7days": 12, - "critical": 2, - "high": 4, - "medium": 4, - "low": 2 - } -} - - -def build_system_prompt() -> str: - """Build Julia AI system prompt with Ferdinand context""" - - client = FERDINAND_DATA["client"] - alerts = FERDINAND_DATA["today_alerts"] - has_critical = any(a["severity"] in ["critical", "high"] for a in alerts) - - alerts_text = "" - for alert in alerts: - emoji = "RED" if alert["severity"] == "critical" else "ORANGE" if alert["severity"] == "high" else "YELLOW" - alerts_text += f" [{emoji}] {alert['type'].replace('_', ' ').upper()} at {alert['time']}" - if alert.get("note"): - alerts_text += f" - {alert['note']}" - if alert.get("location"): - alerts_text += f" ({alert['location']})" - alerts_text += "\n" - - return f"""You are Julia, a compassionate AI wellness assistant for WellNuo app. -You help caregivers monitor their loved ones' wellbeing. - -CRITICAL: You are ALWAYS talking about {client['name']} (the beneficiary), NOT about yourself! - -BENEFICIARY INFORMATION: -- Name: {client['name']} -- Address: {client['address']} -- Monitoring Period: Last 7 days - -TODAY'S ALERTS: -{alerts_text} - -7-DAY SUMMARY: -- Total alerts: {FERDINAND_DATA['summary']['total_alerts_7days']} -- Critical: {FERDINAND_DATA['summary']['critical']} -- High: {FERDINAND_DATA['summary']['high']} -- Medium: {FERDINAND_DATA['summary']['medium']} -- Low: {FERDINAND_DATA['summary']['low']} - -CONVERSATION RULES: -1. When user asks "how are you?" or "how's it going?" - ALWAYS respond about {client['name']}'s status, NOT about yourself as AI - - NEVER say "I'm doing well as an AI" - the user wants to know about their loved one! - -2. When user asks "what's happening?" or "any updates?" - report {client['name']}'s current status and alerts - -3. ALWAYS assume questions are about {client['name']} unless explicitly about app features - -RESPONSE STYLE - BE CONCISE, NOT PUSHY: -- DON'T overwhelm with information immediately -- First give a SHORT summary, then ASK if they want details -- Example opening: "Hi! {'I have some important updates about ' + client['name'] + '. Would you like to hear them?' if has_critical else client['name'] + ' is doing well today. Anything specific you would like to know?'}" -- Wait for user to ask before giving long explanations -- Keep initial responses to 1-2 sentences max -- Only elaborate when user asks "tell me more", "what happened?", etc. - -BAD (too pushy): "Hi! Ferdinand had a fall at 6:32 AM in the bathroom, his sleep was only 5 hours, he missed his morning medication..." -GOOD (concise): "Hi! I have some concerns about {client['name']} today - there was an incident this morning. Want me to tell you more?" - -You're speaking with a caregiver who cares deeply about {client['name']}.""" - - -class JuliaAssistant(Agent): - """Julia AI Voice Assistant for WellNuo""" - - def __init__(self) -> None: - super().__init__( - instructions=build_system_prompt(), - ) - - -# Create the agent server -server = agents.AgentServer() - - -@server.rtc_session() -async def julia_session(ctx: agents.JobContext): - """Main voice session handler""" - - # Create the agent session with STT, LLM, TTS - session = AgentSession( - stt=deepgram.STT(model="nova-2"), - llm=openai.LLM( - model="gpt-4o", - api_key=os.getenv("OPENAI_API_KEY"), - ), - tts=deepgram.TTS(model="aura-asteria-en"), - vad=silero.VAD.load(), - ) - - # Start the session - await session.start( - room=ctx.room, - agent=JuliaAssistant(), - ) - - # Generate initial greeting - await session.generate_reply( - instructions="Greet the user warmly. If there are critical alerts, mention you have important updates. Keep it brief - 1 sentence max." - ) - - -if __name__ == "__main__": - agents.cli.run_app(server) diff --git a/julia-agent/julia-ai/pyproject.toml b/julia-agent/julia-ai/pyproject.toml index 22746ca..09ebec4 100644 --- a/julia-agent/julia-ai/pyproject.toml +++ b/julia-agent/julia-ai/pyproject.toml @@ -12,7 +12,6 @@ dependencies = [ "livekit-agents[silero]~=1.3", "livekit-plugins-noise-cancellation~=0.2", "livekit-plugins-deepgram~=1.0", - "livekit-plugins-openai~=1.0", "python-dotenv", "aiohttp", ] diff --git a/julia-agent/julia-ai/src/agent.py b/julia-agent/julia-ai/src/agent.py index 68ace34..27d5f5e 100644 --- a/julia-agent/julia-ai/src/agent.py +++ b/julia-agent/julia-ai/src/agent.py @@ -4,6 +4,7 @@ LiveKit Agents Cloud deployment Uses WellNuo ask_wellnuo_ai API for LLM responses, Deepgram for STT/TTS """ +import json import logging import os import random @@ -140,10 +141,17 @@ def normalize_question(user_message: str) -> str: class WellNuoLLM(llm.LLM): """Custom LLM that uses WellNuo ask_wellnuo_ai API.""" - def __init__(self): + def __init__( + self, + deployment_id: str | None = None, + beneficiary_names_dict: dict | None = None, + ): super().__init__() self._token = None self._model_name = "wellnuo-voice-ask" + # Dynamic values from participant metadata (or fallback to env/defaults) + self._deployment_id = deployment_id or DEPLOYMENT_ID + self._beneficiary_names_dict = beneficiary_names_dict or {} @property def model(self) -> str: @@ -199,8 +207,16 @@ class WellNuoLLM(llm.LLM): "user_name": WELLNUO_USER, "token": token, "question": normalized_question, - "deployment_id": DEPLOYMENT_ID, + "deployment_id": self._deployment_id, } + # Add beneficiary_names_dict if available + if self._beneficiary_names_dict: + data["beneficiary_names_dict"] = json.dumps( + self._beneficiary_names_dict + ) + logger.info( + f"Using beneficiary_names_dict: {self._beneficiary_names_dict}" + ) async with session.post(WELLNUO_API_URL, data=data) as resp: result = await resp.json() @@ -290,6 +306,39 @@ def prewarm(proc: JobProcess): proc.userdata["vad"] = silero.VAD.load() +def extract_beneficiary_data(ctx: JobContext) -> tuple[str | None, dict | None]: + """ + Extract deployment_id and beneficiary_names_dict from participant metadata. + + The mobile app passes this data through the LiveKit token metadata: + { + "deploymentId": "21", + "beneficiaryNamesDict": {"21": "papa", "69": "David"} + } + """ + deployment_id = None + beneficiary_names_dict = None + + # Get remote participants (the user who joined) + for participant in ctx.room.remote_participants.values(): + metadata = participant.metadata + if metadata: + try: + data = json.loads(metadata) + deployment_id = data.get("deploymentId") + beneficiary_names_dict = data.get("beneficiaryNamesDict") + logger.info( + f"Extracted from participant {participant.identity}: " + f"deployment_id={deployment_id}, " + f"beneficiary_names_dict={beneficiary_names_dict}" + ) + break # Use first participant with metadata + except json.JSONDecodeError: + logger.warning(f"Failed to parse participant metadata: {metadata}") + + return deployment_id, beneficiary_names_dict + + async def entrypoint(ctx: JobContext): """Main Julia AI voice session handler.""" @@ -297,13 +346,28 @@ async def entrypoint(ctx: JobContext): await ctx.connect() logger.info(f"Starting Julia AI session in room {ctx.room.name}") - logger.info(f"Using WellNuo ask_wellnuo_ai API with deployment_id: {DEPLOYMENT_ID}") + + # Extract beneficiary data from participant metadata + deployment_id, beneficiary_names_dict = extract_beneficiary_data(ctx) + + # Log what we're using + effective_deployment_id = deployment_id or DEPLOYMENT_ID + logger.info( + f"Using WellNuo ask_wellnuo_ai API with deployment_id: {effective_deployment_id}" + ) + if beneficiary_names_dict: + logger.info(f"Beneficiary names dict: {beneficiary_names_dict}") + else: + logger.info("No beneficiary_names_dict provided, using default behavior") session = AgentSession( # Deepgram Nova-2 for accurate speech-to-text stt=deepgram.STT(model="nova-2"), - # WellNuo voice_ask API for LLM - llm=WellNuoLLM(), + # WellNuo voice_ask API for LLM with dynamic beneficiary data + llm=WellNuoLLM( + deployment_id=deployment_id, + beneficiary_names_dict=beneficiary_names_dict, + ), # Deepgram Aura Asteria for natural female voice tts=deepgram.TTS(model="aura-asteria-en"), # Silero VAD for voice activity detection diff --git a/julia-agent/julia-ai/uv.lock b/julia-agent/julia-ai/uv.lock index 2108d19..486609d 100644 --- a/julia-agent/julia-ai/uv.lock +++ b/julia-agent/julia-ai/uv.lock @@ -751,7 +751,6 @@ dependencies = [ { name = "livekit-agents", extra = ["silero"] }, { name = "livekit-plugins-deepgram" }, { name = "livekit-plugins-noise-cancellation" }, - { name = "livekit-plugins-openai" }, { name = "python-dotenv" }, ] @@ -768,7 +767,6 @@ requires-dist = [ { name = "livekit-agents", extras = ["silero"], specifier = "~=1.3" }, { name = "livekit-plugins-deepgram", specifier = "~=1.0" }, { name = "livekit-plugins-noise-cancellation", specifier = "~=0.2" }, - { name = "livekit-plugins-openai", specifier = "~=1.0" }, { name = "python-dotenv" }, ] @@ -844,9 +842,6 @@ codecs = [ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "numpy", version = "2.4.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, ] -images = [ - { name = "pillow" }, -] silero = [ { name = "livekit-plugins-silero" }, ] @@ -923,19 +918,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9f/4d/37be8da861607f392d07bb0f1c6b57c635db249095084abcbfaaaab6d7b5/livekit_plugins_noise_cancellation-0.2.5-py3-none-win_amd64.whl", hash = "sha256:5879d28120a6b47a7d557832d9432683710987f79e9b514171898be36534380b", size = 65757107, upload-time = "2025-06-30T14:49:59.053Z" }, ] -[[package]] -name = "livekit-plugins-openai" -version = "1.3.11" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "livekit-agents", extra = ["codecs", "images"] }, - { name = "openai", extra = ["realtime"] }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e3/30/44a724703548e729280f4a420ac3ec8d58b61dd4e79fff529060689f147f/livekit_plugins_openai-1.3.11.tar.gz", hash = "sha256:61d77152f96213003b9bdea48c86a44a07a70456a41c664e82a2b5ae99a7f72a", size = 48754, upload-time = "2026-01-14T18:45:46.685Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/68/1093471d954f24789e8a17d2f56deaa3831d86a0edbc747a63b8eb49c113/livekit_plugins_openai-1.3.11-py3-none-any.whl", hash = "sha256:c54964cd987fa8a9e341f66bb30baeb02bfeea62a87eebaf19ae52b0486e8224", size = 56582, upload-time = "2026-01-14T18:45:45.744Z" }, -] - [[package]] name = "livekit-plugins-silero" version = "1.3.11" @@ -1289,11 +1271,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b5/df/c306f7375d42bafb379934c2df4c2fa3964656c8c782bac75ee10c102818/openai-2.15.0-py3-none-any.whl", hash = "sha256:6ae23b932cd7230f7244e52954daa6602716d6b9bf235401a107af731baea6c3", size = 1067879, upload-time = "2026-01-09T22:10:06.446Z" }, ] -[package.optional-dependencies] -realtime = [ - { name = "websockets" }, -] - [[package]] name = "opentelemetry-api" version = "1.39.1" @@ -1416,79 +1393,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, ] -[[package]] -name = "pillow" -version = "12.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d0/02/d52c733a2452ef1ffcc123b68e6606d07276b0e358db70eabad7e40042b7/pillow-12.1.0.tar.gz", hash = "sha256:5c5ae0a06e9ea030ab786b0251b32c7e4ce10e58d983c0d5c56029455180b5b9", size = 46977283, upload-time = "2026-01-02T09:13:29.892Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/41/f73d92b6b883a579e79600d391f2e21cb0df767b2714ecbd2952315dfeef/pillow-12.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:fb125d860738a09d363a88daa0f59c4533529a90e564785e20fe875b200b6dbd", size = 5304089, upload-time = "2026-01-02T09:10:24.953Z" }, - { url = "https://files.pythonhosted.org/packages/94/55/7aca2891560188656e4a91ed9adba305e914a4496800da6b5c0a15f09edf/pillow-12.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cad302dc10fac357d3467a74a9561c90609768a6f73a1923b0fd851b6486f8b0", size = 4657815, upload-time = "2026-01-02T09:10:27.063Z" }, - { url = "https://files.pythonhosted.org/packages/e9/d2/b28221abaa7b4c40b7dba948f0f6a708bd7342c4d47ce342f0ea39643974/pillow-12.1.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a40905599d8079e09f25027423aed94f2823adaf2868940de991e53a449e14a8", size = 6222593, upload-time = "2026-01-02T09:10:29.115Z" }, - { url = "https://files.pythonhosted.org/packages/71/b8/7a61fb234df6a9b0b479f69e66901209d89ff72a435b49933f9122f94cac/pillow-12.1.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:92a7fe4225365c5e3a8e598982269c6d6698d3e783b3b1ae979e7819f9cd55c1", size = 8027579, upload-time = "2026-01-02T09:10:31.182Z" }, - { url = "https://files.pythonhosted.org/packages/ea/51/55c751a57cc524a15a0e3db20e5cde517582359508d62305a627e77fd295/pillow-12.1.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f10c98f49227ed8383d28174ee95155a675c4ed7f85e2e573b04414f7e371bda", size = 6335760, upload-time = "2026-01-02T09:10:33.02Z" }, - { url = "https://files.pythonhosted.org/packages/dc/7c/60e3e6f5e5891a1a06b4c910f742ac862377a6fe842f7184df4a274ce7bf/pillow-12.1.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8637e29d13f478bc4f153d8daa9ffb16455f0a6cb287da1b432fdad2bfbd66c7", size = 7027127, upload-time = "2026-01-02T09:10:35.009Z" }, - { url = "https://files.pythonhosted.org/packages/06/37/49d47266ba50b00c27ba63a7c898f1bb41a29627ced8c09e25f19ebec0ff/pillow-12.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:21e686a21078b0f9cb8c8a961d99e6a4ddb88e0fc5ea6e130172ddddc2e5221a", size = 6449896, upload-time = "2026-01-02T09:10:36.793Z" }, - { url = "https://files.pythonhosted.org/packages/f9/e5/67fd87d2913902462cd9b79c6211c25bfe95fcf5783d06e1367d6d9a741f/pillow-12.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2415373395a831f53933c23ce051021e79c8cd7979822d8cc478547a3f4da8ef", size = 7151345, upload-time = "2026-01-02T09:10:39.064Z" }, - { url = "https://files.pythonhosted.org/packages/bd/15/f8c7abf82af68b29f50d77c227e7a1f87ce02fdc66ded9bf603bc3b41180/pillow-12.1.0-cp310-cp310-win32.whl", hash = "sha256:e75d3dba8fc1ddfec0cd752108f93b83b4f8d6ab40e524a95d35f016b9683b09", size = 6325568, upload-time = "2026-01-02T09:10:41.035Z" }, - { url = "https://files.pythonhosted.org/packages/d4/24/7d1c0e160b6b5ac2605ef7d8be537e28753c0db5363d035948073f5513d7/pillow-12.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:64efdf00c09e31efd754448a383ea241f55a994fd079866b92d2bbff598aad91", size = 7032367, upload-time = "2026-01-02T09:10:43.09Z" }, - { url = "https://files.pythonhosted.org/packages/f4/03/41c038f0d7a06099254c60f618d0ec7be11e79620fc23b8e85e5b31d9a44/pillow-12.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:f188028b5af6b8fb2e9a76ac0f841a575bd1bd396e46ef0840d9b88a48fdbcea", size = 2452345, upload-time = "2026-01-02T09:10:44.795Z" }, - { url = "https://files.pythonhosted.org/packages/43/c4/bf8328039de6cc22182c3ef007a2abfbbdab153661c0a9aa78af8d706391/pillow-12.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:a83e0850cb8f5ac975291ebfc4170ba481f41a28065277f7f735c202cd8e0af3", size = 5304057, upload-time = "2026-01-02T09:10:46.627Z" }, - { url = "https://files.pythonhosted.org/packages/43/06/7264c0597e676104cc22ca73ee48f752767cd4b1fe084662620b17e10120/pillow-12.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b6e53e82ec2db0717eabb276aa56cf4e500c9a7cec2c2e189b55c24f65a3e8c0", size = 4657811, upload-time = "2026-01-02T09:10:49.548Z" }, - { url = "https://files.pythonhosted.org/packages/72/64/f9189e44474610daf83da31145fa56710b627b5c4c0b9c235e34058f6b31/pillow-12.1.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:40a8e3b9e8773876d6e30daed22f016509e3987bab61b3b7fe309d7019a87451", size = 6232243, upload-time = "2026-01-02T09:10:51.62Z" }, - { url = "https://files.pythonhosted.org/packages/ef/30/0df458009be6a4caca4ca2c52975e6275c387d4e5c95544e34138b41dc86/pillow-12.1.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:800429ac32c9b72909c671aaf17ecd13110f823ddb7db4dfef412a5587c2c24e", size = 8037872, upload-time = "2026-01-02T09:10:53.446Z" }, - { url = "https://files.pythonhosted.org/packages/e4/86/95845d4eda4f4f9557e25381d70876aa213560243ac1a6d619c46caaedd9/pillow-12.1.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b022eaaf709541b391ee069f0022ee5b36c709df71986e3f7be312e46f42c84", size = 6345398, upload-time = "2026-01-02T09:10:55.426Z" }, - { url = "https://files.pythonhosted.org/packages/5c/1f/8e66ab9be3aaf1435bc03edd1ebdf58ffcd17f7349c1d970cafe87af27d9/pillow-12.1.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f345e7bc9d7f368887c712aa5054558bad44d2a301ddf9248599f4161abc7c0", size = 7034667, upload-time = "2026-01-02T09:10:57.11Z" }, - { url = "https://files.pythonhosted.org/packages/f9/f6/683b83cb9b1db1fb52b87951b1c0b99bdcfceaa75febf11406c19f82cb5e/pillow-12.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d70347c8a5b7ccd803ec0c85c8709f036e6348f1e6a5bf048ecd9c64d3550b8b", size = 6458743, upload-time = "2026-01-02T09:10:59.331Z" }, - { url = "https://files.pythonhosted.org/packages/9a/7d/de833d63622538c1d58ce5395e7c6cb7e7dce80decdd8bde4a484e095d9f/pillow-12.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1fcc52d86ce7a34fd17cb04e87cfdb164648a3662a6f20565910a99653d66c18", size = 7159342, upload-time = "2026-01-02T09:11:01.82Z" }, - { url = "https://files.pythonhosted.org/packages/8c/40/50d86571c9e5868c42b81fe7da0c76ca26373f3b95a8dd675425f4a92ec1/pillow-12.1.0-cp311-cp311-win32.whl", hash = "sha256:3ffaa2f0659e2f740473bcf03c702c39a8d4b2b7ffc629052028764324842c64", size = 6328655, upload-time = "2026-01-02T09:11:04.556Z" }, - { url = "https://files.pythonhosted.org/packages/6c/af/b1d7e301c4cd26cd45d4af884d9ee9b6fab893b0ad2450d4746d74a6968c/pillow-12.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:806f3987ffe10e867bab0ddad45df1148a2b98221798457fa097ad85d6e8bc75", size = 7031469, upload-time = "2026-01-02T09:11:06.538Z" }, - { url = "https://files.pythonhosted.org/packages/48/36/d5716586d887fb2a810a4a61518a327a1e21c8b7134c89283af272efe84b/pillow-12.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:9f5fefaca968e700ad1a4a9de98bf0869a94e397fe3524c4c9450c1445252304", size = 2452515, upload-time = "2026-01-02T09:11:08.226Z" }, - { url = "https://files.pythonhosted.org/packages/20/31/dc53fe21a2f2996e1b7d92bf671cdb157079385183ef7c1ae08b485db510/pillow-12.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a332ac4ccb84b6dde65dbace8431f3af08874bf9770719d32a635c4ef411b18b", size = 5262642, upload-time = "2026-01-02T09:11:10.138Z" }, - { url = "https://files.pythonhosted.org/packages/ab/c1/10e45ac9cc79419cedf5121b42dcca5a50ad2b601fa080f58c22fb27626e/pillow-12.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:907bfa8a9cb790748a9aa4513e37c88c59660da3bcfffbd24a7d9e6abf224551", size = 4657464, upload-time = "2026-01-02T09:11:12.319Z" }, - { url = "https://files.pythonhosted.org/packages/ad/26/7b82c0ab7ef40ebede7a97c72d473bda5950f609f8e0c77b04af574a0ddb/pillow-12.1.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:efdc140e7b63b8f739d09a99033aa430accce485ff78e6d311973a67b6bf3208", size = 6234878, upload-time = "2026-01-02T09:11:14.096Z" }, - { url = "https://files.pythonhosted.org/packages/76/25/27abc9792615b5e886ca9411ba6637b675f1b77af3104710ac7353fe5605/pillow-12.1.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bef9768cab184e7ae6e559c032e95ba8d07b3023c289f79a2bd36e8bf85605a5", size = 8044868, upload-time = "2026-01-02T09:11:15.903Z" }, - { url = "https://files.pythonhosted.org/packages/0a/ea/f200a4c36d836100e7bc738fc48cd963d3ba6372ebc8298a889e0cfc3359/pillow-12.1.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:742aea052cf5ab5034a53c3846165bc3ce88d7c38e954120db0ab867ca242661", size = 6349468, upload-time = "2026-01-02T09:11:17.631Z" }, - { url = "https://files.pythonhosted.org/packages/11/8f/48d0b77ab2200374c66d344459b8958c86693be99526450e7aee714e03e4/pillow-12.1.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a6dfc2af5b082b635af6e08e0d1f9f1c4e04d17d4e2ca0ef96131e85eda6eb17", size = 7041518, upload-time = "2026-01-02T09:11:19.389Z" }, - { url = "https://files.pythonhosted.org/packages/1d/23/c281182eb986b5d31f0a76d2a2c8cd41722d6fb8ed07521e802f9bba52de/pillow-12.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:609e89d9f90b581c8d16358c9087df76024cf058fa693dd3e1e1620823f39670", size = 6462829, upload-time = "2026-01-02T09:11:21.28Z" }, - { url = "https://files.pythonhosted.org/packages/25/ef/7018273e0faac099d7b00982abdcc39142ae6f3bd9ceb06de09779c4a9d6/pillow-12.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:43b4899cfd091a9693a1278c4982f3e50f7fb7cff5153b05174b4afc9593b616", size = 7166756, upload-time = "2026-01-02T09:11:23.559Z" }, - { url = "https://files.pythonhosted.org/packages/8f/c8/993d4b7ab2e341fe02ceef9576afcf5830cdec640be2ac5bee1820d693d4/pillow-12.1.0-cp312-cp312-win32.whl", hash = "sha256:aa0c9cc0b82b14766a99fbe6084409972266e82f459821cd26997a488a7261a7", size = 6328770, upload-time = "2026-01-02T09:11:25.661Z" }, - { url = "https://files.pythonhosted.org/packages/a7/87/90b358775a3f02765d87655237229ba64a997b87efa8ccaca7dd3e36e7a7/pillow-12.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:d70534cea9e7966169ad29a903b99fc507e932069a881d0965a1a84bb57f6c6d", size = 7033406, upload-time = "2026-01-02T09:11:27.474Z" }, - { url = "https://files.pythonhosted.org/packages/5d/cf/881b457eccacac9e5b2ddd97d5071fb6d668307c57cbf4e3b5278e06e536/pillow-12.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:65b80c1ee7e14a87d6a068dd3b0aea268ffcabfe0498d38661b00c5b4b22e74c", size = 2452612, upload-time = "2026-01-02T09:11:29.309Z" }, - { url = "https://files.pythonhosted.org/packages/dd/c7/2530a4aa28248623e9d7f27316b42e27c32ec410f695929696f2e0e4a778/pillow-12.1.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:7b5dd7cbae20285cdb597b10eb5a2c13aa9de6cde9bb64a3c1317427b1db1ae1", size = 4062543, upload-time = "2026-01-02T09:11:31.566Z" }, - { url = "https://files.pythonhosted.org/packages/8f/1f/40b8eae823dc1519b87d53c30ed9ef085506b05281d313031755c1705f73/pillow-12.1.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:29a4cef9cb672363926f0470afc516dbf7305a14d8c54f7abbb5c199cd8f8179", size = 4138373, upload-time = "2026-01-02T09:11:33.367Z" }, - { url = "https://files.pythonhosted.org/packages/d4/77/6fa60634cf06e52139fd0e89e5bbf055e8166c691c42fb162818b7fda31d/pillow-12.1.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:681088909d7e8fa9e31b9799aaa59ba5234c58e5e4f1951b4c4d1082a2e980e0", size = 3601241, upload-time = "2026-01-02T09:11:35.011Z" }, - { url = "https://files.pythonhosted.org/packages/4f/bf/28ab865de622e14b747f0cd7877510848252d950e43002e224fb1c9ababf/pillow-12.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:983976c2ab753166dc66d36af6e8ec15bb511e4a25856e2227e5f7e00a160587", size = 5262410, upload-time = "2026-01-02T09:11:36.682Z" }, - { url = "https://files.pythonhosted.org/packages/1c/34/583420a1b55e715937a85bd48c5c0991598247a1fd2eb5423188e765ea02/pillow-12.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:db44d5c160a90df2d24a24760bbd37607d53da0b34fb546c4c232af7192298ac", size = 4657312, upload-time = "2026-01-02T09:11:38.535Z" }, - { url = "https://files.pythonhosted.org/packages/1d/fd/f5a0896839762885b3376ff04878f86ab2b097c2f9a9cdccf4eda8ba8dc0/pillow-12.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6b7a9d1db5dad90e2991645874f708e87d9a3c370c243c2d7684d28f7e133e6b", size = 6232605, upload-time = "2026-01-02T09:11:40.602Z" }, - { url = "https://files.pythonhosted.org/packages/98/aa/938a09d127ac1e70e6ed467bd03834350b33ef646b31edb7452d5de43792/pillow-12.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6258f3260986990ba2fa8a874f8b6e808cf5abb51a94015ca3dc3c68aa4f30ea", size = 8041617, upload-time = "2026-01-02T09:11:42.721Z" }, - { url = "https://files.pythonhosted.org/packages/17/e8/538b24cb426ac0186e03f80f78bc8dc7246c667f58b540bdd57c71c9f79d/pillow-12.1.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e115c15e3bc727b1ca3e641a909f77f8ca72a64fff150f666fcc85e57701c26c", size = 6346509, upload-time = "2026-01-02T09:11:44.955Z" }, - { url = "https://files.pythonhosted.org/packages/01/9a/632e58ec89a32738cabfd9ec418f0e9898a2b4719afc581f07c04a05e3c9/pillow-12.1.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6741e6f3074a35e47c77b23a4e4f2d90db3ed905cb1c5e6e0d49bff2045632bc", size = 7038117, upload-time = "2026-01-02T09:11:46.736Z" }, - { url = "https://files.pythonhosted.org/packages/c7/a2/d40308cf86eada842ca1f3ffa45d0ca0df7e4ab33c83f81e73f5eaed136d/pillow-12.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:935b9d1aed48fcfb3f838caac506f38e29621b44ccc4f8a64d575cb1b2a88644", size = 6460151, upload-time = "2026-01-02T09:11:48.625Z" }, - { url = "https://files.pythonhosted.org/packages/f1/88/f5b058ad6453a085c5266660a1417bdad590199da1b32fb4efcff9d33b05/pillow-12.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5fee4c04aad8932da9f8f710af2c1a15a83582cfb884152a9caa79d4efcdbf9c", size = 7164534, upload-time = "2026-01-02T09:11:50.445Z" }, - { url = "https://files.pythonhosted.org/packages/19/ce/c17334caea1db789163b5d855a5735e47995b0b5dc8745e9a3605d5f24c0/pillow-12.1.0-cp313-cp313-win32.whl", hash = "sha256:a786bf667724d84aa29b5db1c61b7bfdde380202aaca12c3461afd6b71743171", size = 6332551, upload-time = "2026-01-02T09:11:52.234Z" }, - { url = "https://files.pythonhosted.org/packages/e5/07/74a9d941fa45c90a0d9465098fe1ec85de3e2afbdc15cc4766622d516056/pillow-12.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:461f9dfdafa394c59cd6d818bdfdbab4028b83b02caadaff0ffd433faf4c9a7a", size = 7040087, upload-time = "2026-01-02T09:11:54.822Z" }, - { url = "https://files.pythonhosted.org/packages/88/09/c99950c075a0e9053d8e880595926302575bc742b1b47fe1bbcc8d388d50/pillow-12.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:9212d6b86917a2300669511ed094a9406888362e085f2431a7da985a6b124f45", size = 2452470, upload-time = "2026-01-02T09:11:56.522Z" }, - { url = "https://files.pythonhosted.org/packages/b5/ba/970b7d85ba01f348dee4d65412476321d40ee04dcb51cd3735b9dc94eb58/pillow-12.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:00162e9ca6d22b7c3ee8e61faa3c3253cd19b6a37f126cad04f2f88b306f557d", size = 5264816, upload-time = "2026-01-02T09:11:58.227Z" }, - { url = "https://files.pythonhosted.org/packages/10/60/650f2fb55fdba7a510d836202aa52f0baac633e50ab1cf18415d332188fb/pillow-12.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7d6daa89a00b58c37cb1747ec9fb7ac3bc5ffd5949f5888657dfddde6d1312e0", size = 4660472, upload-time = "2026-01-02T09:12:00.798Z" }, - { url = "https://files.pythonhosted.org/packages/2b/c0/5273a99478956a099d533c4f46cbaa19fd69d606624f4334b85e50987a08/pillow-12.1.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e2479c7f02f9d505682dc47df8c0ea1fc5e264c4d1629a5d63fe3e2334b89554", size = 6268974, upload-time = "2026-01-02T09:12:02.572Z" }, - { url = "https://files.pythonhosted.org/packages/b4/26/0bf714bc2e73d5267887d47931d53c4ceeceea6978148ed2ab2a4e6463c4/pillow-12.1.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f188d580bd870cda1e15183790d1cc2fa78f666e76077d103edf048eed9c356e", size = 8073070, upload-time = "2026-01-02T09:12:04.75Z" }, - { url = "https://files.pythonhosted.org/packages/43/cf/1ea826200de111a9d65724c54f927f3111dc5ae297f294b370a670c17786/pillow-12.1.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0fde7ec5538ab5095cc02df38ee99b0443ff0e1c847a045554cf5f9af1f4aa82", size = 6380176, upload-time = "2026-01-02T09:12:06.626Z" }, - { url = "https://files.pythonhosted.org/packages/03/e0/7938dd2b2013373fd85d96e0f38d62b7a5a262af21ac274250c7ca7847c9/pillow-12.1.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0ed07dca4a8464bada6139ab38f5382f83e5f111698caf3191cb8dbf27d908b4", size = 7067061, upload-time = "2026-01-02T09:12:08.624Z" }, - { url = "https://files.pythonhosted.org/packages/86/ad/a2aa97d37272a929a98437a8c0ac37b3cf012f4f8721e1bd5154699b2518/pillow-12.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f45bd71d1fa5e5749587613037b172e0b3b23159d1c00ef2fc920da6f470e6f0", size = 6491824, upload-time = "2026-01-02T09:12:10.488Z" }, - { url = "https://files.pythonhosted.org/packages/a4/44/80e46611b288d51b115826f136fb3465653c28f491068a72d3da49b54cd4/pillow-12.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:277518bf4fe74aa91489e1b20577473b19ee70fb97c374aa50830b279f25841b", size = 7190911, upload-time = "2026-01-02T09:12:12.772Z" }, - { url = "https://files.pythonhosted.org/packages/86/77/eacc62356b4cf81abe99ff9dbc7402750044aed02cfd6a503f7c6fc11f3e/pillow-12.1.0-cp313-cp313t-win32.whl", hash = "sha256:7315f9137087c4e0ee73a761b163fc9aa3b19f5f606a7fc08d83fd3e4379af65", size = 6336445, upload-time = "2026-01-02T09:12:14.775Z" }, - { url = "https://files.pythonhosted.org/packages/e7/3c/57d81d0b74d218706dafccb87a87ea44262c43eef98eb3b164fd000e0491/pillow-12.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:0ddedfaa8b5f0b4ffbc2fa87b556dc59f6bb4ecb14a53b33f9189713ae8053c0", size = 7045354, upload-time = "2026-01-02T09:12:16.599Z" }, - { url = "https://files.pythonhosted.org/packages/ac/82/8b9b97bba2e3576a340f93b044a3a3a09841170ab4c1eb0d5c93469fd32f/pillow-12.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:80941e6d573197a0c28f394753de529bb436b1ca990ed6e765cf42426abc39f8", size = 2454547, upload-time = "2026-01-02T09:12:18.704Z" }, - { url = "https://files.pythonhosted.org/packages/8b/bc/224b1d98cffd7164b14707c91aac83c07b047fbd8f58eba4066a3e53746a/pillow-12.1.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ca94b6aac0d7af2a10ba08c0f888b3d5114439b6b3ef39968378723622fed377", size = 5228605, upload-time = "2026-01-02T09:13:14.084Z" }, - { url = "https://files.pythonhosted.org/packages/0c/ca/49ca7769c4550107de049ed85208240ba0f330b3f2e316f24534795702ce/pillow-12.1.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:351889afef0f485b84078ea40fe33727a0492b9af3904661b0abbafee0355b72", size = 4622245, upload-time = "2026-01-02T09:13:15.964Z" }, - { url = "https://files.pythonhosted.org/packages/73/48/fac807ce82e5955bcc2718642b94b1bd22a82a6d452aea31cbb678cddf12/pillow-12.1.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bb0984b30e973f7e2884362b7d23d0a348c7143ee559f38ef3eaab640144204c", size = 5247593, upload-time = "2026-01-02T09:13:17.913Z" }, - { url = "https://files.pythonhosted.org/packages/d2/95/3e0742fe358c4664aed4fd05d5f5373dcdad0b27af52aa0972568541e3f4/pillow-12.1.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:84cabc7095dd535ca934d57e9ce2a72ffd216e435a84acb06b2277b1de2689bd", size = 6989008, upload-time = "2026-01-02T09:13:20.083Z" }, - { url = "https://files.pythonhosted.org/packages/5a/74/fe2ac378e4e202e56d50540d92e1ef4ff34ed687f3c60f6a121bcf99437e/pillow-12.1.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:53d8b764726d3af1a138dd353116f774e3862ec7e3794e0c8781e30db0f35dfc", size = 5313824, upload-time = "2026-01-02T09:13:22.405Z" }, - { url = "https://files.pythonhosted.org/packages/f3/77/2a60dee1adee4e2655ac328dd05c02a955c1cd683b9f1b82ec3feb44727c/pillow-12.1.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5da841d81b1a05ef940a8567da92decaa15bc4d7dedb540a8c219ad83d91808a", size = 5963278, upload-time = "2026-01-02T09:13:24.706Z" }, - { url = "https://files.pythonhosted.org/packages/2d/71/64e9b1c7f04ae0027f788a248e6297d7fcc29571371fe7d45495a78172c0/pillow-12.1.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:75af0b4c229ac519b155028fa1be632d812a519abba9b46b20e50c6caa184f19", size = 7029809, upload-time = "2026-01-02T09:13:26.541Z" }, -] - [[package]] name = "pluggy" version = "1.6.0" @@ -2091,65 +1995,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6e/d4/ed38dd3b1767193de971e694aa544356e63353c33a85d948166b5ff58b9e/watchfiles-1.1.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e6f39af2eab0118338902798b5aa6664f46ff66bc0280de76fca67a7f262a49", size = 457546, upload-time = "2025-10-14T15:06:13.372Z" }, ] -[[package]] -name = "websockets" -version = "15.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" }, - { url = "https://files.pythonhosted.org/packages/1c/9f/9d11c1a4eb046a9e106483b9ff69bce7ac880443f00e5ce64261b47b07e7/websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", size = 173080, upload-time = "2025-03-05T20:01:37.304Z" }, - { url = "https://files.pythonhosted.org/packages/d5/4f/b462242432d93ea45f297b6179c7333dd0402b855a912a04e7fc61c0d71f/websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a", size = 173329, upload-time = "2025-03-05T20:01:39.668Z" }, - { url = "https://files.pythonhosted.org/packages/6e/0c/6afa1f4644d7ed50284ac59cc70ef8abd44ccf7d45850d989ea7310538d0/websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e", size = 182312, upload-time = "2025-03-05T20:01:41.815Z" }, - { url = "https://files.pythonhosted.org/packages/dd/d4/ffc8bd1350b229ca7a4db2a3e1c482cf87cea1baccd0ef3e72bc720caeec/websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf", size = 181319, upload-time = "2025-03-05T20:01:43.967Z" }, - { url = "https://files.pythonhosted.org/packages/97/3a/5323a6bb94917af13bbb34009fac01e55c51dfde354f63692bf2533ffbc2/websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb", size = 181631, upload-time = "2025-03-05T20:01:46.104Z" }, - { url = "https://files.pythonhosted.org/packages/a6/cc/1aeb0f7cee59ef065724041bb7ed667b6ab1eeffe5141696cccec2687b66/websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d", size = 182016, upload-time = "2025-03-05T20:01:47.603Z" }, - { url = "https://files.pythonhosted.org/packages/79/f9/c86f8f7af208e4161a7f7e02774e9d0a81c632ae76db2ff22549e1718a51/websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9", size = 181426, upload-time = "2025-03-05T20:01:48.949Z" }, - { url = "https://files.pythonhosted.org/packages/c7/b9/828b0bc6753db905b91df6ae477c0b14a141090df64fb17f8a9d7e3516cf/websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c", size = 181360, upload-time = "2025-03-05T20:01:50.938Z" }, - { url = "https://files.pythonhosted.org/packages/89/fb/250f5533ec468ba6327055b7d98b9df056fb1ce623b8b6aaafb30b55d02e/websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256", size = 176388, upload-time = "2025-03-05T20:01:52.213Z" }, - { url = "https://files.pythonhosted.org/packages/1c/46/aca7082012768bb98e5608f01658ff3ac8437e563eca41cf068bd5849a5e/websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41", size = 176830, upload-time = "2025-03-05T20:01:53.922Z" }, - { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423, upload-time = "2025-03-05T20:01:56.276Z" }, - { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082, upload-time = "2025-03-05T20:01:57.563Z" }, - { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330, upload-time = "2025-03-05T20:01:59.063Z" }, - { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878, upload-time = "2025-03-05T20:02:00.305Z" }, - { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883, upload-time = "2025-03-05T20:02:03.148Z" }, - { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252, upload-time = "2025-03-05T20:02:05.29Z" }, - { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521, upload-time = "2025-03-05T20:02:07.458Z" }, - { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958, upload-time = "2025-03-05T20:02:09.842Z" }, - { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918, upload-time = "2025-03-05T20:02:11.968Z" }, - { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388, upload-time = "2025-03-05T20:02:13.32Z" }, - { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828, upload-time = "2025-03-05T20:02:14.585Z" }, - { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" }, - { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" }, - { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" }, - { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" }, - { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" }, - { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" }, - { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" }, - { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" }, - { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" }, - { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" }, - { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" }, - { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" }, - { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" }, - { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" }, - { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" }, - { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" }, - { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" }, - { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, - { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, - { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, - { url = "https://files.pythonhosted.org/packages/02/9e/d40f779fa16f74d3468357197af8d6ad07e7c5a27ea1ca74ceb38986f77a/websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", size = 173109, upload-time = "2025-03-05T20:03:17.769Z" }, - { url = "https://files.pythonhosted.org/packages/bc/cd/5b887b8585a593073fd92f7c23ecd3985cd2c3175025a91b0d69b0551372/websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", size = 173343, upload-time = "2025-03-05T20:03:19.094Z" }, - { url = "https://files.pythonhosted.org/packages/fe/ae/d34f7556890341e900a95acf4886833646306269f899d58ad62f588bf410/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", size = 174599, upload-time = "2025-03-05T20:03:21.1Z" }, - { url = "https://files.pythonhosted.org/packages/71/e6/5fd43993a87db364ec60fc1d608273a1a465c0caba69176dd160e197ce42/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", size = 174207, upload-time = "2025-03-05T20:03:23.221Z" }, - { url = "https://files.pythonhosted.org/packages/2b/fb/c492d6daa5ec067c2988ac80c61359ace5c4c674c532985ac5a123436cec/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", size = 174155, upload-time = "2025-03-05T20:03:25.321Z" }, - { url = "https://files.pythonhosted.org/packages/68/a1/dcb68430b1d00b698ae7a7e0194433bce4f07ded185f0ee5fb21e2a2e91e/websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", size = 176884, upload-time = "2025-03-05T20:03:27.934Z" }, - { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, -] - [[package]] name = "yarl" version = "1.22.0" diff --git a/julia-agent/requirements.txt b/julia-agent/requirements.txt index b12edf2..870e454 100644 --- a/julia-agent/requirements.txt +++ b/julia-agent/requirements.txt @@ -1,4 +1,4 @@ livekit-agents[silero]~=1.3 livekit-plugins-deepgram~=1.0 -livekit-plugins-openai~=1.0 python-dotenv~=1.0 +aiohttp~=3.9 diff --git a/package-lock.json b/package-lock.json index 0e85e11..4a3fb8c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,6 +41,7 @@ "react-dom": "19.1.0", "react-native": "0.81.5", "react-native-gesture-handler": "~2.28.0", + "react-native-keyboard-controller": "^1.20.6", "react-native-reanimated": "~4.1.1", "react-native-safe-area-context": "~5.6.0", "react-native-screens": "~4.16.0", @@ -11329,6 +11330,20 @@ "react-native": "*" } }, + "node_modules/react-native-keyboard-controller": { + "version": "1.20.6", + "resolved": "https://registry.npmjs.org/react-native-keyboard-controller/-/react-native-keyboard-controller-1.20.6.tgz", + "integrity": "sha512-RS6FjIjTFtAMQGdcXp3m6jUs1XgDa8qkpO5c4ix1S5HS0z3L2E1LUOY5rD73YUADOO3MfQN1z3JkHdBtzKucbg==", + "license": "MIT", + "dependencies": { + "react-native-is-edge-to-edge": "^1.2.1" + }, + "peerDependencies": { + "react": "*", + "react-native": "*", + "react-native-reanimated": ">=3.0.0" + } + }, "node_modules/react-native-reanimated": { "version": "4.1.6", "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.1.6.tgz", diff --git a/package.json b/package.json index f55852e..3a222b9 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "react-dom": "19.1.0", "react-native": "0.81.5", "react-native-gesture-handler": "~2.28.0", + "react-native-keyboard-controller": "^1.20.6", "react-native-reanimated": "~4.1.1", "react-native-safe-area-context": "~5.6.0", "react-native-screens": "~4.16.0", diff --git a/services/livekitService.ts b/services/livekitService.ts index 9c08e61..e2efe17 100644 --- a/services/livekitService.ts +++ b/services/livekitService.ts @@ -11,6 +11,12 @@ const JULIA_TOKEN_SERVER = 'https://wellnuo.smartlaunchhub.com/julia'; export const VOICE_ID = 'Asteria'; export const VOICE_NAME = 'Asteria'; +// Beneficiary data to pass to voice agent +export interface BeneficiaryData { + deploymentId: string; + beneficiaryNamesDict: Record; +} + // API Response types export interface LiveKitTokenResponse { success: boolean; @@ -25,10 +31,18 @@ export interface LiveKitTokenResponse { /** * Get a LiveKit access token from Julia Token Server * No authentication required - token server is dedicated for voice AI + * @param userId - User identifier + * @param beneficiaryData - Optional beneficiary data to pass to voice agent */ -export async function getToken(userId: string): Promise { +export async function getToken( + userId: string, + beneficiaryData?: BeneficiaryData +): Promise { try { console.log('[LiveKit] Getting token for user:', userId); + if (beneficiaryData) { + console.log('[LiveKit] With beneficiary data:', beneficiaryData); + } // Request LiveKit token from Julia Token Server const response = await fetch(`${JULIA_TOKEN_SERVER}/token`, { @@ -36,7 +50,7 @@ export async function getToken(userId: string): Promise { headers: { 'Content-Type': 'application/json', }, - body: JSON.stringify({ userId }), + body: JSON.stringify({ userId, beneficiaryData }), }); if (!response.ok) {