| 414 | |
| 415 | |
| 416 | class StreamingJobManager: |
| 417 | def __init__(self) -> None: |
| 418 | self._lock = threading.Lock() |
| 419 | self._jobs: dict[str, StreamingJob] = {} |
| 420 | |
| 421 | def create(self) -> StreamingJob: |
| 422 | stream_id = f"stream-{int(time.time() * 1000)}-{uuid.uuid4().hex[:8]}" |
| 423 | job = StreamingJob(stream_id=stream_id) |
| 424 | with self._lock: |
| 425 | self._jobs[stream_id] = job |
| 426 | return job |
| 427 | |
| 428 | def get(self, stream_id: str) -> StreamingJob | None: |
| 429 | with self._lock: |
| 430 | return self._jobs.get(stream_id) |
| 431 | |
| 432 | def close(self, stream_id: str) -> StreamingJob | None: |
| 433 | with self._lock: |
| 434 | job = self._jobs.get(stream_id) |
| 435 | if job is None: |
| 436 | return None |
| 437 | with job.lock: |
| 438 | job.is_closed = True |
| 439 | job.state = "closed" if job.state not in {"done", "failed"} else job.state |
| 440 | try: |
| 441 | job.audio_queue.put_nowait(None) |
| 442 | except queue.Full: |
| 443 | pass |
| 444 | return job |
| 445 | |
| 446 | def delete(self, stream_id: str) -> StreamingJob | None: |
| 447 | with self._lock: |
| 448 | return self._jobs.pop(stream_id, None) |
| 449 | |
| 450 | |
| 451 | def _warmup_status_text(snapshot: WarmupSnapshot) -> str: |