New web interface, move llm engine to separate process
This commit is contained in:
102
sia/chat_io_buffer.py
Normal file
102
sia/chat_io_buffer.py
Normal file
@@ -0,0 +1,102 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import List, Callable
|
||||
from enum import Enum
|
||||
import datetime
|
||||
|
||||
from .io_buffer import IOBuffer
|
||||
from .util import format_timestamp
|
||||
|
||||
class MessageType(Enum):
|
||||
USER = "user"
|
||||
ASSISTANT = "assistant"
|
||||
|
||||
@dataclass
|
||||
class ChatMessage:
|
||||
id: str # Formatted timestamp
|
||||
content: str
|
||||
message_type: MessageType
|
||||
|
||||
class ChatIOBuffer(IOBuffer):
|
||||
def __init__(self):
|
||||
self._messages: List[ChatMessage] = []
|
||||
self._last_read_timestamp: str = format_timestamp(datetime.datetime.now())
|
||||
self._change_handlers: List[Callable] = []
|
||||
|
||||
@property
|
||||
def messages(self) -> List[ChatMessage]:
|
||||
return self._messages.copy()
|
||||
|
||||
@property
|
||||
def last_read_timestamp(self) -> str:
|
||||
return self._last_read_timestamp
|
||||
|
||||
def read(self) -> str:
|
||||
unread_messages = self._unread_messages()
|
||||
self._last_read_timestamp = self._format_now()
|
||||
self._notify_handlers([], [])
|
||||
return unread_messages
|
||||
|
||||
def write(self, content: str) -> None:
|
||||
message = ChatMessage(
|
||||
id=self._format_now(),
|
||||
content=content,
|
||||
message_type=MessageType.ASSISTANT
|
||||
)
|
||||
self._messages.append(message)
|
||||
self._notify_handlers(
|
||||
new_messages=[message],
|
||||
deleted_message_ids=[]
|
||||
)
|
||||
|
||||
def buffer_length(self) -> int:
|
||||
return len(self._unread_messages())
|
||||
|
||||
def add_user_message(self, content: str):
|
||||
message = ChatMessage(
|
||||
id=self._format_now(),
|
||||
content=content,
|
||||
message_type=MessageType.USER
|
||||
)
|
||||
self._messages.append(message)
|
||||
self._notify_handlers(
|
||||
new_messages=[message],
|
||||
deleted_message_ids=[]
|
||||
)
|
||||
|
||||
def delete_message(self, message_id: str):
|
||||
for i, msg in enumerate(self._messages):
|
||||
if msg.id == message_id:
|
||||
self._messages.pop(i)
|
||||
self._notify_handlers(
|
||||
new_messages=[],
|
||||
deleted_message_ids=[message_id]
|
||||
)
|
||||
break
|
||||
|
||||
def clear(self) -> None:
|
||||
deleted_ids = [msg.id for msg in self._messages]
|
||||
self._messages.clear()
|
||||
self._last_read_timestamp = self._format_now()
|
||||
self._notify_handlers(
|
||||
new_messages=[],
|
||||
deleted_message_ids=deleted_ids
|
||||
)
|
||||
|
||||
def add_change_handler(self, handler: Callable[[
|
||||
List[ChatMessage], # new messages
|
||||
List[str], # deleted message ids
|
||||
str # last read timestamp
|
||||
], None]) -> None:
|
||||
self._change_handlers.append(handler)
|
||||
|
||||
def _notify_handlers(self, new_messages: List[ChatMessage],
|
||||
deleted_message_ids: List[str]) -> None:
|
||||
for handler in self._change_handlers:
|
||||
handler(new_messages, deleted_message_ids, self._last_read_timestamp)
|
||||
|
||||
def _unread_messages(self) -> List[ChatMessage]:
|
||||
return "\n".join(msg.content for msg in self._messages
|
||||
if msg.message_type == MessageType.USER and msg.id > self._last_read_timestamp)
|
||||
|
||||
def _format_now(self) -> str:
|
||||
return format_timestamp(datetime.datetime.now())
|
||||
Reference in New Issue
Block a user