import sys from PyQt5.QtGui import QIcon from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit,QHBoxLayout, QLineEdit, QVBoxLayout, QWidget, QToolBar, QAction, QPushButton, QStatusBar, QComboBox from PyQt5.QtSvg import QSvgWidget from socketio.client import Client from socketio.exceptions import ConnectionError from pathlib import Path class ServerConnector(QObject): text_chunk_received = pyqtSignal(str) text_generated = pyqtSignal(str) connection_failed = pyqtSignal() connection_status_changed = pyqtSignal(bool) personalities_received = pyqtSignal(list) def __init__(self, parent=None): super(ServerConnector, self).__init__(parent) self.socketio = Client() self.connected = False self.personalities = [] self.selected_personality_id = 0 self.socketio.on('connect', self.handle_connect) self.socketio.on('text_chunk', self.handle_text_chunk) self.socketio.on('text_generated', self.handle_text_generated) self.socketio.on('active_personalities_list', self.handle_personalities_received) def handle_connect(self): self.socketio.emit('connect') self.list_personalities() def connect_to_server(self): if not self.connected: try: self.socketio.connect('http://localhost:9600') self.connected = True self.connection_status_changed.emit(True) except ConnectionError: self.connection_failed.emit() self.connection_status_changed.emit(False) def disconnect_from_server(self): if self.connected: self.socketio.disconnect() self.connected = False self.connection_status_changed.emit(False) def list_personalities(self): self.socketio.emit('list_active_personalities') @pyqtSlot(str) def generate_text(self, prompt): if not self.connected: self.connection_failed.emit() return data = { 'client_id': self.socketio.sid, 'prompt': prompt, 'personality': self.selected_personality_id } self.socketio.emit('generate_text', data) def handle_personalities_list(self, data): personalities = data['personalities'] self.personalities_list_received.emit(personalities) def handle_text_chunk(self, data): chunk = data['chunk'] self.text_chunk_received.emit(chunk) def handle_text_generated(self, data): text = data['text'] self.text_generated.emit(text) def handle_personalities_received(self, data): personalities = data['personalities'] print(f"Received List of personalities:{personalities}") self.personalities = personalities self.personalities_received.emit(personalities) class MainWindow(QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setWindowTitle("AIPersonality Client") self.user_input_layout = QHBoxLayout() self.user_text = QLineEdit() self.text_edit = QTextEdit() self.toolbar = QToolBar() self.submit_button = QPushButton("Submit") self.user_input_layout.addWidget(self.user_text) self.user_input_layout.addWidget(self.submit_button) self.statusbar = QStatusBar() self.personality_combo_box = QComboBox() self.personality_combo_box.setMinimumWidth(500) self.connect_action = QAction(QIcon(str(Path(__file__).parent/'assets/connected.svg')), "", self) self.connect_action.setCheckable(True) self.connect_action.toggled.connect(self.toggle_connection) self.toolbar.addAction(self.connect_action) self.toolbar.addWidget(self.personality_combo_box) self.addToolBar(self.toolbar) layout = QVBoxLayout() layout.addLayout(self.user_input_layout) layout.addWidget(self.text_edit) widget = QWidget() widget.setLayout(layout) self.setCentralWidget(widget) self.connector = ServerConnector() self.connector.text_chunk_received.connect(self.handle_text_chunk) self.connector.text_generated.connect(self.handle_text_generated) self.connector.connection_failed.connect(self.handle_connection_failed) self.connector.connection_status_changed.connect(self.handle_connection_status_changed) self.connector.personalities_received.connect(self.handle_personalities_received) self.connector.connect_to_server() self.submit_button.clicked.connect(self.submit_text) self.setStatusBar(self.statusbar) self.update_statusbar() @pyqtSlot(bool) def toggle_connection(self, checked): if checked: self.connector.connect_to_server() self.connect_action.setIcon(QIcon(str(Path(__file__).parent/'assets/connected.svg'))) else: self.connector.disconnect_from_server() self.connect_action.setIcon(QIcon(str(Path(__file__).parent/'assets/disconnected.svg'))) @pyqtSlot() def submit_text(self): prompt = self.user_text.text() self.selected_personality_id = self.personality_combo_box.currentIndex() self.text_edit.insertPlainText("User:"+prompt+"\n"+self.connector.personalities[self.selected_personality_id]+":") self.connector.generate_text(prompt) @pyqtSlot(str) def handle_text_chunk(self, chunk): self.text_edit.insertPlainText(chunk) @pyqtSlot(str) def handle_text_generated(self, text): self.text_edit.append(text) @pyqtSlot() def handle_connection_failed(self): self.text_edit.append("Failed to connect to the server.") @pyqtSlot(bool) def handle_connection_status_changed(self, connected): if connected: self.statusbar.showMessage("Connected to the server") else: self.statusbar.showMessage("Disconnected from the server") @pyqtSlot(list) def handle_personalities_received(self, personalities): print("Received personalities") self.personality_combo_box.clear() self.personality_combo_box.addItems(personalities) def update_statusbar(self): if self.connector.connected: self.statusbar.showMessage("Connected to the server") self.connect_action.setIcon(QIcon(str(Path(__file__).parent/'assets/connected.svg'))) else: self.statusbar.showMessage("Disconnected from the server") self.connect_action.setIcon(QIcon(str(Path(__file__).parent/'assets/disconnected.svg'))) if __name__ == '__main__': app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec_())