Assistant: 
User: import sys
import asyncio
import nest_asyncio
from g4f.client import AsyncClient
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, 
                             QHBoxLayout, QLabel, QTextEdit, QPushButton, 
                             QComboBox, QScrollArea, QSizePolicy)
from PyQt5.QtCore import Qt, QEvent

# Apply nest_asyncio to allow nested event loops
nest_asyncio.apply()

# Create an AsyncClient instance
client = AsyncClient()

# Updated list of available models
available_models = {
    "ChatGPT": ["gpt-3.5-turbo", "gpt-4", "gpt-4o"],
    "Gemini": ["gemini-pro", "gemini-flash", "gemini-1"],
    "Claude": ["claude-3", "claude-3.5-sonnet", "claude-3.5-haiku"],
    "LLaMA": ["llama-3.1-70b", "llama-3.1-8b", "llama-3.2-11b"],
    "Qwen": ["qwen-2-72b", "qwen-1.5-14b", "qwen-1.5-7b"],
}

# Create a flattened list of model names for the combo box
model_list = [f"{provider} - {model}" 
              for provider, models in available_models.items() 
              for model in models]

class ChatbotApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Chatbot GUI")
        self.setGeometry(100, 100, 600, 400)
        self.setStyleSheet("background-color: #222; color: #fff;")

        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)

        self.layout = QVBoxLayout(self.central_widget)

        # Dropdown menu
        self.model_selector = QComboBox(self)
        self.model_selector.addItems(model_list)
        self.layout.addWidget(self.model_selector)

        # Scroll area for chat display
        self.scroll_area = QScrollArea()
        self.scroll_area.setWidgetResizable(True)
        self.scroll_area.setStyleSheet("background-color: #222; border: none;")
        self.scroll_area_widget = QWidget()
        self.scroll_area_layout = QVBoxLayout(self.scroll_area_widget)
        self.scroll_area_layout.setAlignment(Qt.AlignTop)
        self.scroll_area.setWidget(self.scroll_area_widget)
        
        # Make the scroll area resizable
        self.scroll_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.layout.addWidget(self.scroll_area)

        # Input box
        self.input_box = QTextEdit(self)
        self.input_box.setPlaceholderText("Type your message and press Enter...")
        self.input_box.setStyleSheet("background-color: #333; color: #fff;")
        self.input_box.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.layout.addWidget(self.input_box)

        # Send button
        self.send_button = QPushButton("Send", self)
        self.send_button.clicked.connect(self.send_message)
        self.layout.addWidget(self.send_button)

        # Connect Enter key event
        self.input_box.installEventFilter(self)

    def eventFilter(self, source, event):
        if event.type() == QEvent.KeyPress and source is self.input_box:
            if event.key() == Qt.Key_Return:
                if event.modifiers() == Qt.ShiftModifier:
                    # Shift + Enter: Insert newline
                    self.input_box.insertPlainText('\n')
                else:
                    # Enter: Send the message
                    self.send_message()
                return True  # Stop further handling of this event
        return super().eventFilter(source, event)

    def send_message(self):
        user_message = self.input_box.toPlainText().strip()
        if user_message:
            self.display_message(user_message, user=True)
            self.input_box.clear()
            asyncio.run(self.get_response(user_message))

    def display_message(self, message, user):
        message_label = QLabel(message)
        message_label.setWordWrap(True)

        # Remove fixed width to make it scalable
        message_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        # Create a copy button
        copy_button = QPushButton("📋")
        copy_button.clicked.connect(lambda: self.copy_to_clipboard(message))

        # Layout for message and copy button
        button_layout = QHBoxLayout()
        button_layout.addWidget(message_label)
        button_layout.addWidget(copy_button)

        # Align the copy button to the top
        button_layout.setAlignment(copy_button, Qt.AlignTop)

        if user:
            button_layout.setAlignment(Qt.AlignRight)
            message_label.setStyleSheet("background-color: #0078D7; border-radius: 5px; padding: 5px;")
        else:
            button_layout.setAlignment(Qt.AlignLeft)
            message_label.setStyleSheet("background-color: #5A5A5A; border-radius: 5px; padding: 5px;")

        self.scroll_area_layout.addLayout(button_layout)
        self.scroll_area.verticalScrollBar().setValue(self.scroll_area.verticalScrollBar().maximum())

    def copy_to_clipboard(self, message):
        clipboard = QApplication.clipboard()
        clipboard.setText(message)

    async def get_response(self, user_message):
        model_index = self.model_selector.currentIndex()
        model = model_list[model_index].split(" - ")[1]
        
        messages = [{"role": "user", "content": user_message}]
        
        try:
            response = await client.chat.completions.create(
                model=model,
                messages=messages
            )
            if hasattr(response, 'choices') and response.choices:
                bot_message = response.choices[0].message.content
                self.display_message(bot_message, user=False)
            else:
                self.display_message("No response from the model.", user=False)

        except Exception as e:
            self.display_message(f"An error occurred: {e}", user=False)

if __name__ == "__main__":
    # Set the event loop policy for Windows
    if sys.platform == "win32":
        asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

    app = QApplication(sys.argv)
    chatbot_app = ChatbotApp()
    chatbot_app.show()
    sys.exit(app.exec_())
Assistant: