Mercurial
comparison dictation/session.py @ 280:49e9e591c9bb
Add persistent dictation, prewarmed WebRTC speech input, Copilot SDK routing, animated conversation lifecycle controls, parking, and architecture coverage.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Tue, 18 Aug 2026 19:14:53 -0700 |
| parents | 78699f810817 |
| children |
comparison
equal
deleted
inserted
replaced
| 279:b3b547563ec7 | 280:49e9e591c9bb |
|---|---|
| 52 def on_open() -> None: | 52 def on_open() -> None: |
| 53 self.send("ready", sessionId=self.session_id) | 53 self.send("ready", sessionId=self.session_id) |
| 54 | 54 |
| 55 @channel.on("message") | 55 @channel.on("message") |
| 56 def on_message(message: Any) -> None: | 56 def on_message(message: Any) -> None: |
| 57 if message == "stop": | 57 if message in {"commit", "pause", "stop"}: |
| 58 self.stopping = True | 58 if message == "stop": |
| 59 self.stopping = True | |
| 60 if self.partial_task and not self.partial_task.done(): | |
| 61 self.partial_task.cancel() | |
| 59 event = self.segmenter.flush() | 62 event = self.segmenter.flush() |
| 60 if event and event.samples is not None: | 63 if event and event.samples is not None: |
| 61 self._start_final(event.samples) | 64 self._start_final(event.samples) |
| 62 else: | 65 else: |
| 63 self.send("speech.ended") | 66 self.send("speech.ended") |
| 153 {"type": event_type, **payload}, | 156 {"type": event_type, **payload}, |
| 154 separators=(",", ":"), | 157 separators=(",", ":"), |
| 155 ) | 158 ) |
| 156 ) | 159 ) |
| 157 | 160 |
| 161 async def _cancel_pending_ice_transactions(self) -> None: | |
| 162 # aioice 0.10.2 can leave STUN retry timers armed after its datagram | |
| 163 # transport closes. Cancel their futures first so Transaction.run() | |
| 164 # clears each timer before RTCPeerConnection.close() drops sockets. | |
| 165 ice_transports = getattr( | |
| 166 self.peer, | |
| 167 "_RTCPeerConnection__iceTransports", | |
| 168 (), | |
| 169 ) | |
| 170 for ice_transport in ice_transports: | |
| 171 connection = getattr(ice_transport, "_connection", None) | |
| 172 for protocol in getattr(connection, "_protocols", ()): | |
| 173 for transaction in tuple( | |
| 174 getattr(protocol, "transactions", {}).values() | |
| 175 ): | |
| 176 future = getattr(transaction, "_Transaction__future", None) | |
| 177 if future is not None and not future.done(): | |
| 178 future.cancel() | |
| 179 await asyncio.sleep(0) | |
| 180 | |
| 158 async def close(self) -> None: | 181 async def close(self) -> None: |
| 159 if self.closed: | 182 if self.closed: |
| 160 return | 183 return |
| 161 self.closed = True | 184 self.closed = True |
| 162 tasks = [ | 185 tasks = [ |
| 172 task.cancel() | 195 task.cancel() |
| 173 if tasks: | 196 if tasks: |
| 174 await asyncio.gather(*tasks, return_exceptions=True) | 197 await asyncio.gather(*tasks, return_exceptions=True) |
| 175 if self.channel and self.channel.readyState != "closed": | 198 if self.channel and self.channel.readyState != "closed": |
| 176 self.channel.close() | 199 self.channel.close() |
| 200 await self._cancel_pending_ice_transactions() | |
| 177 await self.peer.close() | 201 await self.peer.close() |