def __init__(self, model_config: Union[str, Path], service_name: str, agent_namespace: str, batch_size: int, utterance_lifetime_sec: int, rabbit_host: str, rabbit_port: int, rabbit_login: str, rabbit_password: str, rabbit_virtualhost: str, loop: asyncio.AbstractEventLoop) -> None: self._add_to_buffer_lock = asyncio.Lock() self._infer_lock = asyncio.Lock() server_params = get_server_params(model_config) self._model_args_names = server_params['model_args_names'] self._model = build_model(model_config) self._in_queue = None self._utterance_lifetime_sec = utterance_lifetime_sec self._batch_size = batch_size self._incoming_messages_buffer = [] loop.run_until_complete( self._connect(loop=loop, host=rabbit_host, port=rabbit_port, login=rabbit_login, password=rabbit_password, virtualhost=rabbit_virtualhost, agent_namespace=agent_namespace)) loop.run_until_complete( self._setup_queues(service_name, agent_namespace)) loop.run_until_complete( self._in_queue.consume(callback=self._on_message_callback)) log.info(f'Service in queue started consuming')
def start_ms_bf_server(model_config: Path, app_id: Optional[str], app_secret: Optional[str], port: Optional[int] = None, https: Optional[bool] = None, ssl_key: Optional[str] = None, ssl_cert: Optional[str] = None) -> None: server_params = get_server_params(model_config) host = server_params['host'] port = port or server_params['port'] ssl_config = get_ssl_params(server_params, https, ssl_key=ssl_key, ssl_cert=ssl_cert) input_q = Queue() bot = MSBot(model_config, input_q, app_id, app_secret) bot.start() endpoint = '/v3/conversations' redirect_root_to_docs(app, 'answer', endpoint, 'post') @app.post(endpoint) async def answer(activity: dict) -> dict: bot.input_queue.put(activity) return {} uvicorn.run(app, host=host, port=port, logger=uvicorn_log, ssl_version=ssl_config.version, ssl_keyfile=ssl_config.keyfile, ssl_certfile=ssl_config.certfile) bot.join()
def interact_api(config_path): server_params = get_server_params(config_path) url_base = 'http://{}:{}'.format(server_params['host'], api_port or server_params['port']) url = urljoin(url_base.replace('http://0.0.0.0:', 'http://127.0.0.1:'), server_params['model_endpoint']) post_headers = {'Accept': 'application/json'} logfile = io.BytesIO(b'') args = [ sys.executable, "-m", "deeppavlov", "riseapi", str(config_path) ] if api_port: args += ['-p', str(api_port)] p = pexpect.popen_spawn.PopenSpawn(' '.join(args), timeout=None, logfile=logfile) try: p.expect(url_base) get_url = urljoin( url_base.replace('http://0.0.0.0:', 'http://127.0.0.1:'), '/api') get_response = requests.get(get_url) response_code = get_response.status_code assert response_code == 200, f"GET /api request returned error code {response_code} with {config_path}" model_args_names = get_response.json() post_payload = dict() for arg_name in model_args_names: arg_value = ' '.join(['qwerty'] * 10) post_payload[arg_name] = [arg_value] post_response = requests.post(url, json=post_payload, headers=post_headers) response_code = post_response.status_code assert response_code == 200, f"POST request returned error code {response_code} with {config_path}" except pexpect.exceptions.EOF: raise RuntimeError('Got unexpected EOF: \n{}'.format( logfile.getvalue().decode())) finally: p.kill(signal.SIGTERM) p.wait()
def start_alice_server(model_config: Union[str, Path], host: Optional[str] = None, port: Optional[int] = None, endpoint: Optional[str] = None, https: Optional[bool] = None, ssl_key: Optional[str] = None, ssl_cert: Optional[str] = None) -> None: server_params = get_server_params(model_config) host = host or server_params['host'] port = port or server_params['port'] endpoint = endpoint or server_params['model_endpoint'] ssl_config = get_ssl_params(server_params, https, ssl_key=ssl_key, ssl_cert=ssl_cert) input_q = Queue() output_q = Queue() bot = AliceBot(model_config, input_q, output_q) bot.start() redirect_root_to_docs(app, 'answer', endpoint, 'post') @app.post(endpoint, summary='A model endpoint', response_description='A model response') async def answer(data: dict = data_body) -> dict: loop = asyncio.get_event_loop() bot.input_queue.put(data) response: dict = await loop.run_in_executor(None, bot.output_queue.get) return response uvicorn.run(app, host=host, port=port, logger=uvicorn_log, ssl_version=ssl_config.version, ssl_keyfile=ssl_config.keyfile, ssl_certfile=ssl_config.certfile) bot.join()
def __init__(self, model_config: Path, socket_type: str, port: Optional[int] = None, socket_file: Optional[Union[str, Path]] = None) -> None: """Initializes socket server. Args: model_config: Path to the config file. socket_type: Socket family. "TCP" for the AF_INET socket server, "UNIX" for UNIX Domain Socket server. port: Port number for the AF_INET address family. If parameter is not defined, the port number from the utils/settings/server_config.json is used. socket_file: Path to the file to which UNIX Domain Socket server connects. If parameter is not defined, the path from the utils/settings/server_config.json is used. Raises: ValueError: If ``socket_type`` parameter is neither "TCP" nor "UNIX". """ server_params = get_server_params(model_config) socket_type = socket_type or server_params['socket_type'] self._loop = asyncio.get_event_loop() if socket_type == 'TCP': host = server_params['host'] port = port or server_params['port'] self._launch_msg = f'{server_params["socket_launch_message"]} http://{host}:{port}' self._loop.create_task( asyncio.start_server(self._handle_client, host, port)) elif socket_type == 'UNIX': socket_file = socket_file or server_params['unix_socket_file'] socket_path = Path(socket_file).resolve() if socket_path.exists(): socket_path.unlink() self._launch_msg = f'{server_params["socket_launch_message"]} {socket_file}' self._loop.create_task( asyncio.start_unix_server(self._handle_client, socket_file)) else: raise ValueError(f'socket type "{socket_type}" is not supported') self._model = build_model(model_config) self._model_args_names = server_params['model_args_names']
def interact_socket(config_path, socket_type): socket_params = get_server_params(config_path) model_args_names = socket_params['model_args_names'] host = socket_params['host'] port = api_port or socket_params['port'] socket_payload = {} for arg_name in model_args_names: arg_value = ' '.join(['qwerty'] * 10) socket_payload[arg_name] = [arg_value] logfile = io.BytesIO(b'') args = [ sys.executable, "-m", "deeppavlov", "risesocket", str(config_path), '--socket-type', socket_type ] if socket_type == 'TCP': args += ['-p', str(port)] address_family = socket.AF_INET connect_arg = (host, port) else: address_family = socket.AF_UNIX connect_arg = socket_params['unix_socket_file'] p = pexpect.popen_spawn.PopenSpawn(' '.join(args), timeout=None, logfile=logfile) try: p.expect(socket_params['socket_launch_message']) with socket.socket(address_family, socket.SOCK_STREAM) as s: try: s.connect(connect_arg) except ConnectionRefusedError: sleep(1) s.connect(connect_arg) s.sendall(encode(socket_payload)) s.settimeout(60) header = s.recv(4) body_len = unpack('<I', header)[0] data = bytearray() while len(data) < body_len: chunk = s.recv(body_len - len(data)) if not chunk: raise ValueError( f'header does not match body\nheader: {body_len}\nbody length: {len(data)}' f'data: {data}') data.extend(chunk) try: resp = json.loads(data) except json.decoder.JSONDecodeError: raise ValueError(f"Can't decode model response {data}") assert resp['status'] == 'OK', f"{socket_type} socket request returned status: {resp['status']}" \ f" with {config_path}\n{logfile.getvalue().decode()}" except pexpect.exceptions.EOF: raise RuntimeError( f'Got unexpected EOF: \n{logfile.getvalue().decode()}') except json.JSONDecodeError: raise ValueError( f'Got JSON not serializable response from model: "{data}"\n{logfile.getvalue().decode()}' ) finally: p.kill(signal.SIGTERM) p.wait()
def start_alexa_server(model_config: Union[str, Path, dict], port: Optional[int] = None, https: Optional[bool] = None, ssl_key: Optional[str] = None, ssl_cert: Optional[str] = None) -> None: """Initiates FastAPI web service with Alexa skill. Allows raise Alexa web service with DeepPavlov config in backend. Args: model_config: DeepPavlov config path. port: FastAPI web service port. https: Flag for running Alexa skill service in https mode. ssl_key: SSL key file path. ssl_cert: SSL certificate file path. """ server_params = get_server_params(model_config) host = server_params['host'] port = port or server_params['port'] ssl_config = get_ssl_params(server_params, https, ssl_key=ssl_key, ssl_cert=ssl_cert) input_q = Queue() output_q = Queue() bot = AlexaBot(model_config, input_q, output_q) bot.start() endpoint = '/interact' redirect_root_to_docs(app, 'interact', endpoint, 'post') @app.post(endpoint, summary='Amazon Alexa custom service endpoint', response_description='A model response') async def interact( data: dict = data_body, signature: str = signature_header, signature_chain_url: str = cert_chain_url_header) -> JSONResponse: # It is necessary for correct data validation to serialize data to a JSON formatted string with separators. request_dict = { 'request_body': json.dumps(data, separators=(',', ':')).encode('utf-8'), 'signature_chain_url': signature_chain_url, 'signature': signature, 'alexa_request': data } bot.input_queue.put(request_dict) loop = asyncio.get_event_loop() response: dict = await loop.run_in_executor(None, bot.output_queue.get) response_code = 400 if 'error' in response.keys() else 200 return JSONResponse(response, status_code=response_code) uvicorn.run(app, host=host, port=port, logger=uvicorn_log, ssl_version=ssl_config.version, ssl_keyfile=ssl_config.keyfile, ssl_certfile=ssl_config.certfile) bot.join()