Browse Source

set up quart (flask) webui

master
Hendrik Langer 11 months ago
parent
commit
cfdbb306bc
  1. 3
      README.md
  2. 0
      matrix_pygmalion_bot/connections/__init__.py
  3. 27
      matrix_pygmalion_bot/connections/templates/index.html
  4. 64
      matrix_pygmalion_bot/connections/webui.py
  5. 71
      matrix_pygmalion_bot/main.py
  6. 3
      requirements.txt

3
README.md

@ -32,3 +32,6 @@ python3 koboldcpp.py --unbantokens --smartcontext --stream models/pygmalion-6b-v
* runpod.io
* vast.ai
* stablehorde.net
## ToDo:
* https://python-poetry.org/

0
matrix_pygmalion_bot/connections/__init__.py

27
matrix_pygmalion_bot/connections/templates/index.html

@ -0,0 +1,27 @@
<script type="text/javascript">
const ws = new WebSocket(`ws://${location.host}/ws`);
ws.addEventListener('message', function (event) {
const li = document.createElement("li");
li.appendChild(document.createTextNode(event.data));
document.getElementById("messages").appendChild(li);
});
function send(event) {
const message = (new FormData(event.target)).get("message");
if (message) {
ws.send(message);
}
event.target.reset();
return false;
}
</script>
<div style="display: flex; height: 100%; flex-direction: column">
<ul id="messages" style="flex-grow: 1; list-style-type: none"></ul>
<form onsubmit="return send(event)">
<input type="text" name="message" minlength="1" />
<button type="submit">Send</button>
</form>
</div>

64
matrix_pygmalion_bot/connections/webui.py

@ -0,0 +1,64 @@
import asyncio
from typing import AsyncGenerator
from quart import Quart, render_template, websocket
import logging
logger = logging.getLogger(__name__)
app = Quart(__name__)
connections = set()
@app.route("/")
async def index():
return await render_template("index.html")
@app.route("/api")
async def json():
return {"hello": "world"}
async def _send() -> None:
connection = asyncio.Queue()
connections.add(connection)
try:
while True:
message = await connection.get()
await websocket.send(message)
finally:
connections.remove(connection)
async def _receive() -> None:
while True:
message = await websocket.receive()
for connection in connections:
await connection.put(message)
@app.websocket("/ws")
async def ws() -> None:
producer = asyncio.create_task(_send())
consumer = asyncio.create_task(_receive())
await asyncio.gather(producer, consumer)
#await websocket.send_json({"hello": "world"})
class WebUI(object):
"""The Web interface."""
def __init__(self):
self.shutdown_event = asyncio.Event()
self.task = None
app.config["PROPAGATE_EXCEPTIONS"] = True
pass
def run_task(self):
return app.run_task(port=5000, debug=True, shutdown_trigger=self.shutdown_event.wait)
async def stop(self):
self.shutdown_event.set()
self.task.cancel() # or close?

71
matrix_pygmalion_bot/main.py

@ -5,7 +5,10 @@ import json
from .utilities.config_parser import read_config
from .bot.core import ChatBot
from .connections.matrix import ChatClient
from .connections.webui import WebUI
import traceback
import signal
import functools
import logging
logger = logging.getLogger(__name__)
@ -13,6 +16,7 @@ logger = logging.getLogger(__name__)
DATA_DIR = './.data'
bots = []
async def main() -> None:
config = read_config('bot.conf')
if config.has_option('DEFAULT', 'log_level'):
@ -28,6 +32,10 @@ async def main() -> None:
elif log_level == 'CRITICAL':
logging.basicConfig(level=logging.CRITICAL)
# loop = asyncio.get_event_loop()
loop = asyncio.get_running_loop()
loop.set_debug(True)
os.makedirs(DATA_DIR, exist_ok=True)
for section in config.sections():
@ -59,38 +67,69 @@ async def main() -> None:
await bot.connect()
bots.append(bot)
try:
webui = WebUI()
async def shutdown(signal, loop):
"""Cleanup tasks and shut down"""
logger.info(f"Received exit signal {signal.name} ...")
await webui.stop()
for bot in bots:
await bot.disconnect()
tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()]
[task.cancel() for task in tasks]
logging.info(f"Cancelling {len(tasks)} outstanding tasks")
await asyncio.gather(*tasks, return_exceptions=True)
logging.info(f"Flushing metrics")
loop.stop()
# loop = asyncio.get_running_loop()
#
# for signame in {'SIGINT', 'SIGTERM'}:
# loop.add_signal_handler(
# getattr(signal, signame),
# functools.partial(ask_exit, signame, loop))
# for signame in {'SIGINT', 'SIGTERM'}:
# loop.add_signal_handler(
# getattr(signal, signame),
# functools.partial(shutdown, signame, loop))
for s in {signal.SIGHUP, signal.SIGTERM, signal.SIGINT}:
loop.add_signal_handler(
s, lambda s=s: asyncio.create_task(shutdown(s, loop)))
try:
if sys.version_info[0] == 3 and sys.version_info[1] < 11:
tasks = []
for bot in bots:
task = asyncio.create_task(bot.connection.sync_forever(timeout=180000, full_state=True)) # 30000
tasks.append(task)
webui.task = asyncio.create_task(webui.run_task())
tasks.append(webui.task)
await asyncio.gather(*tasks)
else:
async with asyncio.TaskGroup() as tg:
for bot in bots:
task = tg.create_task(bot.connection.sync_forever(timeout=180000, full_state=True)) # 30000
webui.task = tg.create_task(webui.run_task())
except Exception:
print(traceback.format_exc())
sys.exit(1)
# except Exception:
# print(traceback.format_exc())
# sys.exit(1)
except (asyncio.CancelledError, KeyboardInterrupt):
print("Received keyboard interrupt.")
for bot in bots:
await bot.disconnect()
sys.exit(0)
# webui.task.cancel()
# for bot in bots:
# await bot.disconnect()
# sys.exit(0)
finally:
pass
#loop.close()
#def ask_exit(signame, loop):
# print("got signal %s: exit" % signame)
# loop.stop()
if __name__ == "__main__":

3
requirements.txt

@ -14,4 +14,5 @@ humanize
psutil
#git+https://github.com/suno-ai/bark.git
#SpeechRecognition
#TTS #(Coqui-TTS or Uberduck ??)
#TTS #(Coqui-TTS or Uberduck ??) TorToiSe??
quart

Loading…
Cancel
Save