11from __future__ import annotations
22
33import subprocess
4+ import time
45from pathlib import Path
56from typing import Literal
67
@@ -116,12 +117,25 @@ def __init__(
116117 vad_options : VoiceActivityDetectionOptions | None ,
117118 binary : str = "whisper-server" ,
118119 autostart : bool = True ,
120+ ready_timeout_s : float | None = 30.0 ,
121+ ready_check_interval_s : float = 0.25 ,
122+ ready_probe_timeout_s : float = 1.0 ,
119123 ) -> None :
124+ if ready_check_interval_s <= 0 :
125+ raise ValueError ("'ready_check_interval_s' must be positive" )
126+ if ready_probe_timeout_s <= 0 :
127+ raise ValueError ("'ready_probe_timeout_s' must be positive" )
128+ if ready_timeout_s is not None and ready_timeout_s < 0 :
129+ raise ValueError ("'ready_timeout_s' must be non-negative or None" )
130+
120131 self ._server_options = server_options
121132 self ._vad_options = vad_options
122133 self ._binary = binary
123134 self ._process : subprocess .Popen [str ] | None = None
124135 self ._base_url = f"http://{ server_options .host } :{ server_options .port } "
136+ self ._ready_timeout = ready_timeout_s
137+ self ._ready_interval = ready_check_interval_s
138+ self ._ready_probe_timeout = ready_probe_timeout_s
125139 if autostart :
126140 self .start ()
127141
@@ -133,7 +147,7 @@ def start(self) -> None:
133147 self ._vad_options ,
134148 self ._binary ,
135149 )
136- self ._process = subprocess .Popen (command )
150+ self ._process = subprocess .Popen (command ) # type:ignore
137151
138152 def __del__ (self ) -> None :
139153 try :
@@ -170,14 +184,60 @@ def is_running(self) -> bool:
170184 return False
171185 return self ._process .poll () is None
172186
187+ def is_ready (self ) -> bool :
188+ if not self .is_running ():
189+ return False
190+ url = self ._get_url ("" )
191+ try :
192+ response = requests .head (url , timeout = self ._ready_probe_timeout )
193+ except requests .RequestException :
194+ return False
195+ if response .status_code < 500 :
196+ return True
197+ if response .status_code in (405 , 501 ):
198+ try :
199+ response = requests .get (url , timeout = self ._ready_probe_timeout )
200+ except requests .RequestException :
201+ return False
202+ return response .status_code < 500
203+ return False
204+
205+ def _wait_until_ready (
206+ self ,
207+ timeout_s : float | None = None ,
208+ poll_interval_s : float | None = None ,
209+ ) -> None :
210+ if poll_interval_s is None :
211+ poll_interval_s = self ._ready_interval
212+ if poll_interval_s is None or poll_interval_s <= 0 :
213+ raise ValueError ("'poll_interval_s' must be positive" )
214+
215+ deadline : float | None
216+ if timeout_s is None :
217+ timeout_s = self ._ready_timeout
218+ if timeout_s is None :
219+ deadline = None
220+ else :
221+ if timeout_s < 0 :
222+ raise ValueError ("'timeout_s' must be non-negative or None" )
223+ deadline = time .monotonic () + timeout_s
224+
225+ while True :
226+ if self .is_ready ():
227+ return
228+ if not self .is_running ():
229+ raise RuntimeError ("WhisperCPP server process exited before it became ready" )
230+ if deadline is not None and time .monotonic () >= deadline :
231+ raise TimeoutError ("Timed out waiting for WhisperCPP server to become ready" )
232+ time .sleep (poll_interval_s )
233+
173234 def inference (
174235 self ,
175236 file : Path ,
176237 temperature : float = 0.0 ,
177238 temperature_inc : float = 0.2 ,
178239 ) -> InferenceJSONVerbose :
179- if not self .is_running ():
180- raise RuntimeError ("WhisperCPP server is not running" )
240+ self ._wait_until_ready ()
181241 url = self ._get_url (self ._server_options .inference_path )
182242 with file .open ("rb" ) as file_handle :
183243 response = requests .post (
@@ -194,8 +254,7 @@ def inference(
194254 return InferenceJSONVerbose (** response_json )
195255
196256 def load (self , model : Path ) -> requests .Response :
197- if not self .is_running ():
198- raise RuntimeError ("WhisperCPP server is not running" )
257+ self ._wait_until_ready ()
199258 url = self ._get_url ("load" )
200259 response = requests .post (
201260 url ,
0 commit comments