first
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import logging
|
||||
import threading
|
||||
from threading import Event
|
||||
|
||||
import uvicorn
|
||||
|
||||
from speech_to_speech.api.openai_realtime.pipeline_unit import PipelineUnit
|
||||
from speech_to_speech.api.openai_realtime.websocket_router import create_app
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RealtimeServer:
|
||||
"""
|
||||
Pipeline handler for the OpenAI Realtime API mode.
|
||||
|
||||
Owns a pool of isolated PipelineUnits and a single uvicorn server.
|
||||
The websocket route claims the next free unit on each accept and releases
|
||||
it on disconnect; once all units are in use, further connections are rejected.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
stop_event: Event,
|
||||
pool: list[PipelineUnit],
|
||||
host: str = "0.0.0.0",
|
||||
port: int = 8765,
|
||||
) -> None:
|
||||
if not pool:
|
||||
raise ValueError("RealtimeServer requires at least one PipelineUnit in the pool")
|
||||
self.stop_event = stop_event
|
||||
self.pool = pool
|
||||
self.host = host
|
||||
self.port = port
|
||||
|
||||
def run(self) -> None:
|
||||
"""Start the FastAPI/uvicorn server (called from a ThreadManager thread)."""
|
||||
app = create_app(pool=self.pool, stop_event=self.stop_event)
|
||||
|
||||
logger.info(
|
||||
f"OpenAI Realtime API starting on ws://{self.host}:{self.port}/v1/realtime (pool size {len(self.pool)})"
|
||||
)
|
||||
|
||||
config = uvicorn.Config(
|
||||
app,
|
||||
host=self.host,
|
||||
port=self.port,
|
||||
log_level="info",
|
||||
)
|
||||
server = uvicorn.Server(config)
|
||||
|
||||
server.install_signal_handlers = lambda: None # type: ignore[attr-defined]
|
||||
|
||||
def _watch_stop() -> None:
|
||||
self.stop_event.wait()
|
||||
server.should_exit = True
|
||||
|
||||
watcher = threading.Thread(target=_watch_stop, daemon=True)
|
||||
watcher.start()
|
||||
|
||||
server.run()
|
||||
Reference in New Issue
Block a user