|
|
import sys |
|
|
import requests |
|
|
import json |
|
|
from PyQt6.QtWidgets import ( |
|
|
QApplication, QWidget, QVBoxLayout, QHBoxLayout, |
|
|
QPushButton, QTextEdit, QLineEdit, QLabel, QComboBox |
|
|
) |
|
|
from PyQt6.QtCore import QTimer, Qt |
|
|
from PyQt6.QtGui import QFont, QCursor, QIcon, QColor, QTextCursor |
|
|
|
|
|
API_BASE = "http://127.0.0.1:7860/api" |
|
|
|
|
|
class ChatClient(QWidget): |
|
|
def __init__(self, token): |
|
|
super().__init__() |
|
|
self.token = token |
|
|
self.ai_typing_timer = None |
|
|
self.ai_text_buffer = "" |
|
|
self.setWindowTitle("AI HUB Desktop Client") |
|
|
self.setWindowIcon(QIcon("favicon.png")) |
|
|
|
|
|
self.init_ui() |
|
|
self.showMaximized() |
|
|
self.setCursor(QCursor(Qt.CursorShape.ArrowCursor)) |
|
|
|
|
|
def init_ui(self): |
|
|
self.layout = QVBoxLayout(self) |
|
|
self.setLayout(self.layout) |
|
|
|
|
|
|
|
|
self.chat_area = QTextEdit() |
|
|
self.chat_area.setReadOnly(True) |
|
|
self.chat_area.setFont(QFont("Consolas", 12)) |
|
|
self.chat_area.setStyleSheet(""" |
|
|
QTextEdit { |
|
|
background-color: #1e1e1e; |
|
|
color: #f1f1f1; |
|
|
border-radius: 10px; |
|
|
padding: 10px; |
|
|
} |
|
|
""") |
|
|
self.layout.addWidget(self.chat_area) |
|
|
|
|
|
|
|
|
self.typing_label = QLabel("") |
|
|
self.typing_label.setStyleSheet("color: #00ff00; font-style: italic;") |
|
|
self.layout.addWidget(self.typing_label) |
|
|
|
|
|
|
|
|
input_layout = QHBoxLayout() |
|
|
self.user_input = QLineEdit() |
|
|
self.user_input.setPlaceholderText("Type your message here...") |
|
|
self.user_input.returnPressed.connect(self.send_message) |
|
|
self.user_input.setStyleSheet(""" |
|
|
QLineEdit { |
|
|
border-radius: 8px; |
|
|
padding: 6px; |
|
|
font-size: 14px; |
|
|
} |
|
|
""") |
|
|
input_layout.addWidget(self.user_input) |
|
|
|
|
|
self.send_button = QPushButton("Send") |
|
|
self.send_button.setStyleSheet(""" |
|
|
QPushButton { |
|
|
background-color: #0078d7; |
|
|
color: white; |
|
|
border-radius: 8px; |
|
|
padding: 6px 12px; |
|
|
} |
|
|
QPushButton:hover { |
|
|
background-color: #005a9e; |
|
|
} |
|
|
""") |
|
|
self.send_button.clicked.connect(self.send_message) |
|
|
input_layout.addWidget(self.send_button) |
|
|
|
|
|
|
|
|
self.model_select = QComboBox() |
|
|
self.model_select.addItems(["qwen", "deepseek"]) |
|
|
self.model_select.setStyleSheet(""" |
|
|
QComboBox { |
|
|
border-radius: 8px; |
|
|
padding: 4px; |
|
|
font-size: 14px; |
|
|
} |
|
|
""") |
|
|
input_layout.addWidget(self.model_select) |
|
|
|
|
|
self.layout.addLayout(input_layout) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def type_ai_message(self, full_text, delay=30): |
|
|
self.ai_text_buffer = full_text |
|
|
self.typing_label.setText("π€ AI is typing...") |
|
|
self.ai_typing_timer = QTimer() |
|
|
self.ai_typing_timer.timeout.connect(self._type_next_char) |
|
|
self.ai_typing_timer.start(delay) |
|
|
|
|
|
def _type_next_char(self): |
|
|
if self.ai_text_buffer: |
|
|
char = self.ai_text_buffer[0] |
|
|
self.chat_area.moveCursor(QTextCursor.MoveOperation.End) |
|
|
self.chat_area.insertPlainText(char) |
|
|
self.ai_text_buffer = self.ai_text_buffer[1:] |
|
|
else: |
|
|
self.ai_typing_timer.stop() |
|
|
self.typing_label.setText("") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def send_message(self): |
|
|
message = self.user_input.text().strip() |
|
|
if not message: |
|
|
return |
|
|
self.chat_area.append(f"π§ {message}") |
|
|
self.user_input.clear() |
|
|
self.typing_label.setText("π€ AI is thinking...") |
|
|
|
|
|
model_choice = self.model_select.currentText() |
|
|
headers = {"Content-Type": "application/json", "Authorization": f"Bearer {self.token}"} |
|
|
|
|
|
try: |
|
|
res = requests.post( |
|
|
f"{API_BASE}/chat", |
|
|
headers=headers, |
|
|
data=json.dumps({"message": message, "model": model_choice, "max_tokens": 200}), |
|
|
timeout=30 |
|
|
) |
|
|
data = res.json() |
|
|
if "response" in data: |
|
|
self.chat_area.append("π€ ") |
|
|
self.type_ai_message(data["response"]) |
|
|
else: |
|
|
self.chat_area.append("Error: " + data.get("error", "Unknown error")) |
|
|
except Exception as e: |
|
|
self.chat_area.append(f"Error sending message: {e}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
|
|
token = "YOUR_JWT_TOKEN_HERE" |
|
|
app = QApplication(sys.argv) |
|
|
window = ChatClient(token) |
|
|
window.show() |
|
|
sys.exit(app.exec()) |
|
|
|