2023-04-23 20:52:43 +02:00
|
|
|
import asyncio
|
2023-05-10 03:49:39 +02:00
|
|
|
import json
|
2023-10-13 06:31:13 +02:00
|
|
|
import ssl
|
2023-04-23 20:52:43 +02:00
|
|
|
from threading import Thread
|
|
|
|
|
2023-10-13 06:31:13 +02:00
|
|
|
from websockets.server import serve
|
|
|
|
|
2023-07-25 23:49:56 +02:00
|
|
|
from extensions.api.util import (
|
|
|
|
build_parameters,
|
|
|
|
try_start_cloudflared,
|
|
|
|
with_api_lock
|
|
|
|
)
|
2023-05-10 03:49:39 +02:00
|
|
|
from modules import shared
|
2023-05-20 23:42:17 +02:00
|
|
|
from modules.chat import generate_chat_reply
|
2023-05-10 03:49:39 +02:00
|
|
|
from modules.text_generation import generate_reply
|
2023-10-13 06:31:13 +02:00
|
|
|
from modules.logging_colors import logger
|
2023-04-23 20:52:43 +02:00
|
|
|
|
|
|
|
PATH = '/api/v1/stream'
|
|
|
|
|
|
|
|
|
2023-07-09 04:21:20 +02:00
|
|
|
@with_api_lock
|
|
|
|
async def _handle_stream_message(websocket, message):
|
|
|
|
message = json.loads(message)
|
2023-04-23 20:52:43 +02:00
|
|
|
|
2023-07-09 04:21:20 +02:00
|
|
|
prompt = message['prompt']
|
|
|
|
generate_params = build_parameters(message)
|
|
|
|
stopping_strings = generate_params.pop('stopping_strings')
|
|
|
|
generate_params['stream'] = True
|
|
|
|
|
|
|
|
generator = generate_reply(
|
|
|
|
prompt, generate_params, stopping_strings=stopping_strings, is_chat=False)
|
|
|
|
|
|
|
|
# As we stream, only send the new bytes.
|
|
|
|
skip_index = 0
|
|
|
|
message_num = 0
|
|
|
|
|
|
|
|
for a in generator:
|
|
|
|
to_send = a[skip_index:]
|
|
|
|
if to_send is None or chr(0xfffd) in to_send: # partial unicode character, don't send it yet.
|
|
|
|
continue
|
|
|
|
|
|
|
|
await websocket.send(json.dumps({
|
|
|
|
'event': 'text_stream',
|
|
|
|
'message_num': message_num,
|
|
|
|
'text': to_send
|
|
|
|
}))
|
|
|
|
|
|
|
|
await asyncio.sleep(0)
|
|
|
|
skip_index += len(to_send)
|
|
|
|
message_num += 1
|
2023-05-20 23:42:17 +02:00
|
|
|
|
2023-07-09 04:21:20 +02:00
|
|
|
await websocket.send(json.dumps({
|
|
|
|
'event': 'stream_end',
|
|
|
|
'message_num': message_num
|
|
|
|
}))
|
2023-04-23 20:52:43 +02:00
|
|
|
|
|
|
|
|
2023-07-09 04:21:20 +02:00
|
|
|
@with_api_lock
|
|
|
|
async def _handle_chat_stream_message(websocket, message):
|
|
|
|
body = json.loads(message)
|
2023-04-23 20:52:43 +02:00
|
|
|
|
2023-07-09 04:21:20 +02:00
|
|
|
user_input = body['user_input']
|
|
|
|
generate_params = build_parameters(body, chat=True)
|
|
|
|
generate_params['stream'] = True
|
|
|
|
regenerate = body.get('regenerate', False)
|
|
|
|
_continue = body.get('_continue', False)
|
2023-06-02 07:09:52 +02:00
|
|
|
|
2023-07-09 04:21:20 +02:00
|
|
|
generator = generate_chat_reply(
|
|
|
|
user_input, generate_params, regenerate=regenerate, _continue=_continue, loading_message=False)
|
2023-04-23 20:52:43 +02:00
|
|
|
|
2023-07-09 04:21:20 +02:00
|
|
|
message_num = 0
|
|
|
|
for a in generator:
|
|
|
|
await websocket.send(json.dumps({
|
|
|
|
'event': 'text_stream',
|
|
|
|
'message_num': message_num,
|
|
|
|
'history': a
|
|
|
|
}))
|
2023-04-23 20:52:43 +02:00
|
|
|
|
2023-07-09 04:21:20 +02:00
|
|
|
await asyncio.sleep(0)
|
|
|
|
message_num += 1
|
|
|
|
|
|
|
|
await websocket.send(json.dumps({
|
|
|
|
'event': 'stream_end',
|
|
|
|
'message_num': message_num
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
|
|
async def _handle_connection(websocket, path):
|
|
|
|
|
|
|
|
if path == '/api/v1/stream':
|
|
|
|
async for message in websocket:
|
|
|
|
await _handle_stream_message(websocket, message)
|
2023-04-23 20:52:43 +02:00
|
|
|
|
2023-05-20 23:42:17 +02:00
|
|
|
elif path == '/api/v1/chat-stream':
|
|
|
|
async for message in websocket:
|
2023-07-09 04:21:20 +02:00
|
|
|
await _handle_chat_stream_message(websocket, message)
|
2023-05-20 23:42:17 +02:00
|
|
|
|
|
|
|
else:
|
|
|
|
print(f'Streaming api: unknown path: {path}')
|
|
|
|
return
|
2023-04-23 20:52:43 +02:00
|
|
|
|
|
|
|
|
|
|
|
async def _run(host: str, port: int):
|
2023-10-13 06:31:13 +02:00
|
|
|
ssl_certfile = shared.args.ssl_certfile
|
|
|
|
ssl_keyfile = shared.args.ssl_keyfile
|
|
|
|
ssl_verify = True if (ssl_keyfile and ssl_certfile) else False
|
|
|
|
if ssl_verify:
|
|
|
|
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
|
|
|
context.load_cert_chain(ssl_certfile, ssl_keyfile)
|
|
|
|
else:
|
|
|
|
context = None
|
|
|
|
|
|
|
|
async with serve(_handle_connection, host, port, ping_interval=None, ssl=context):
|
|
|
|
await asyncio.Future() # Run the server forever
|
2023-04-23 20:52:43 +02:00
|
|
|
|
|
|
|
|
2023-08-09 03:20:27 +02:00
|
|
|
def _run_server(port: int, share: bool = False, tunnel_id=str):
|
2023-04-23 20:52:43 +02:00
|
|
|
address = '0.0.0.0' if shared.args.listen else '127.0.0.1'
|
2023-10-13 06:31:13 +02:00
|
|
|
ssl_certfile = shared.args.ssl_certfile
|
|
|
|
ssl_keyfile = shared.args.ssl_keyfile
|
|
|
|
ssl_verify = True if (ssl_keyfile and ssl_certfile) else False
|
2023-04-23 20:52:43 +02:00
|
|
|
|
|
|
|
def on_start(public_url: str):
|
|
|
|
public_url = public_url.replace('https://', 'wss://')
|
2023-10-13 06:31:13 +02:00
|
|
|
logger.info(f'Starting streaming server at public url {public_url}{PATH}')
|
2023-04-23 20:52:43 +02:00
|
|
|
|
|
|
|
if share:
|
|
|
|
try:
|
2023-08-09 03:20:27 +02:00
|
|
|
try_start_cloudflared(port, tunnel_id, max_attempts=3, on_start=on_start)
|
2023-04-23 20:52:43 +02:00
|
|
|
except Exception as e:
|
|
|
|
print(e)
|
|
|
|
else:
|
2023-10-13 06:31:13 +02:00
|
|
|
if ssl_verify:
|
|
|
|
logger.info(f'Starting streaming server at wss://{address}:{port}{PATH}')
|
|
|
|
else:
|
|
|
|
logger.info(f'Starting streaming server at ws://{address}:{port}{PATH}')
|
2023-04-23 20:52:43 +02:00
|
|
|
|
|
|
|
asyncio.run(_run(host=address, port=port))
|
|
|
|
|
|
|
|
|
2023-08-09 03:20:27 +02:00
|
|
|
def start_server(port: int, share: bool = False, tunnel_id=str):
|
|
|
|
Thread(target=_run_server, args=[port, share, tunnel_id], daemon=True).start()
|