import sys
import io
import os

sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding='utf-8')

from g4f.client import Client
from PyQt6.QtCore import pyqtSlot
from PyQt6.QtWidgets import QApplication, QMainWindow, QMessageBox
from Authorization import Ui_Authorization
from Registration import Ui_Registration
from MainWindow import Ui_MainWindow
from PyQt6.QtWidgets import QFileDialog
from docx import Document

DATA_FILE = "user_data.txt"

client = Client()

class AuthorizationWindow(QMainWindow, Ui_Authorization):
    def __init__(self):
        super(AuthorizationWindow, self).__init__()
        self.setupUi(self)

        self.pushButton_3.clicked.connect(self.open_registration)
        self.pushButton.clicked.connect(self.login)
        self.user_data = self.load_user_data()

    def load_user_data(self):
        if not os.path.exists(DATA_FILE):
            return {}

        user_data = {}
        with open(DATA_FILE, "r") as file:
            for line in file:
                parts = line.strip().split(",")
                if len(parts) == 2:
                    username, password = parts
                    email = ""
                elif len(parts) == 3:
                    username, password, email = parts
                else:
                    continue
                user_data[username] = {"password": password, "email": email}
        return user_data

    def save_user_data(self):
        with open(DATA_FILE, "w") as file:
            for username, data in self.user_data.items():
                file.write(f"{username},{data['password']},{data['email']}\n")

    @pyqtSlot()
    def open_registration(self):
        self.registration_window = RegistrationWindow(self)
        self.registration_window.show()

    @pyqtSlot()
    def login(self):
        username = self.lineEdit.text()
        password = self.lineEdit_2.text()

        msg_box = QMessageBox(self)
        msg_box.setStyleSheet("background-color: white;")

        if username in self.user_data and self.user_data[username]["password"] == password:
            msg_box.setText("Вы успешно вошли в систему!")
            msg_box.setIcon(QMessageBox.Icon.Information)

            self.main_window = MainWindowWindow(self)
            self.main_window.show()
            self.close()
        else:
            msg_box.setText("Неверный логин или пароль!")
            msg_box.setIcon(QMessageBox.Icon.Warning)

        msg_box.exec()


class RegistrationWindow(QMainWindow, Ui_Registration):
    def __init__(self, auth_window):
        super(RegistrationWindow, self).__init__()
        self.setupUi(self)
        self.auth_window = auth_window
        self.pushButton.clicked.connect(self.save_registration)

    @pyqtSlot()
    def save_registration(self):
        email = self.lineEdit_3.text()
        username = self.lineEdit.text()
        password = self.lineEdit_2.text()
        confirm_password = self.lineEdit_4.text()

        msg_box = QMessageBox(self)
        msg_box.setStyleSheet("background-color: white;")

        if password != confirm_password:
            msg_box.setText("Пароли не совпадают!")
            msg_box.setIcon(QMessageBox.Icon.Warning)
            msg_box.exec()
            return

        self.auth_window.user_data[username] = {"password": password, "email": email}
        self.auth_window.save_user_data()
        msg_box.setText("Регистрация успешна!")
        msg_box.setIcon(QMessageBox.Icon.Information)
        msg_box.exec()

        self.close()


class MainWindowWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, auth_window):
        super(MainWindowWindow, self).__init__()
        self.setupUi(self)
        self.auth_window = auth_window
        self.initialize_signals()

        # Initialize the first tab display
        self.tabWidget.setCurrentIndex(0)

        self.label_139.setWordWrap(True)

    def initialize_signals(self):
        # Connect comboBox signals to methods
        self.comboBox_3.currentIndexChanged.connect(self.handle_comboBox_3_change)
        self.comboBox_6.currentIndexChanged.connect(self.handle_comboBox_6_change)

        # Connect pushButton signals to methods
        self.pushButton_2.clicked.connect(self.handle_push_button_2)
        self.pushButton_3.clicked.connect(self.handle_push_button_3)

        self.pushButton_2.clicked.connect(self.switch_to_tab8)
        self.pushButton_3.clicked.connect(self.switch_to_tab7)

        self.pushButton_4.clicked.connect(self.handle_addition)
        self.pushButton_5.clicked.connect(self.save_to_docx)

    def handle_comboBox_3_change(self, index):
        if index == 0:  # Index for "1"
            self.tabWidget.setCurrentIndex(0)  # Set to tab3
        elif index == 1:  # Index for "2"
            self.tabWidget.setCurrentIndex(1)  # Set to tab4

    def handle_comboBox_6_change(self, index):
        if index == 0:  # Index for "3"
            self.tabWidget.setCurrentIndex(2)  # Set to tab5

    def handle_push_button_2(self):
        # Set tabWidget to tab2
        self.tabWidget_3.setCurrentIndex(1)

    def handle_push_button_3(self):
        # Set tabWidget to tab (initial tab)
        self.tabWidget_3.setCurrentIndex(0)

    def switch_to_tab8(self):
        # Change the active tab in tabWidget3 to tab7
        self.tabWidget_2.setCurrentIndex(1)

    def switch_to_tab7(self):
        # Change the active tab in tabWidget3 to tab6
        self.tabWidget_2.setCurrentIndex(0)


    def handle_addition(self):
        def set_label_text(label, value):
            label.setText(str(round(value, 3)))

        def handle_calculation(expression, label):
            try:
                result = eval(expression)
                if isinstance(result, float):
                    set_label_text(label, result)
                else:
                    raise ValueError("Result is not a float")
            except Exception:
                label.setText("Ошибка ввода")

        calculations = [
            (f"({self.lineEdit_110.text()} + {self.lineEdit_126.text()}) / {self.lineEdit_86.text()}", self.label_156),
            (f"({self.lineEdit_86.text()} - {self.lineEdit_29.text()}) / {self.lineEdit_23.text()}", self.label_172),
            (f"{self.lineEdit_86.text()} / {self.lineEdit_127.text()}", self.label_180),
            (f"{self.lineEdit_86.text()} / ({self.lineEdit_110.text()} + {self.lineEdit_126.text()})", self.label_164),
            (f"({self.lineEdit_86.text()} + {self.lineEdit_110.text()}) / {self.lineEdit_127.text()}", self.label_148),
            (f"({self.lineEdit_116.text()} + {self.lineEdit_146.text()}) / {self.lineEdit_93.text()}", self.label_158),
            (f"({self.lineEdit_93.text()} - {self.lineEdit_47.text()}) / {self.lineEdit_66.text()}", self.label_173),
            (f"{self.lineEdit_93.text()} / {self.lineEdit_147.text()}", self.label_181),
            (f"{self.lineEdit_93.text()} / ({self.lineEdit_116.text()} + {self.lineEdit_146.text()})", self.label_165),
            (f"({self.lineEdit_93.text()} + {self.lineEdit_116.text()}) / {self.lineEdit_147.text()}", self.label_149),
            (f"({self.lineEdit_117.text()} + {self.lineEdit_145.text()}) / {self.lineEdit_100.text()}", self.label_157),
            (f"({self.lineEdit_100.text()} - {self.lineEdit_48.text()}) / {self.lineEdit_71.text()}", self.label_174),
            (f"{self.lineEdit_100.text()} / {self.lineEdit_148.text()}", self.label_182),
            (f"{self.lineEdit_100.text()} / ({self.lineEdit_117.text()} + {self.lineEdit_145.text()})", self.label_166),
            (f"({self.lineEdit_100.text()} + {self.lineEdit_117.text()}) / {self.lineEdit_148.text()}", self.label_150)
        ]

        for expression, label in calculations:
            handle_calculation(expression, label)

        # Вывод в labels
        def handle_comparison(label_current, label_previous, label_diff, label_ratio, label_percent):
            try:
                current_value = float(label_current.text())
                previous_value = float(label_previous.text())

                if previous_value == 0:
                    label_diff.setText("Ошибка деления на ноль")
                    label_ratio.setText("Ошибка деления на ноль")
                    label_percent.setText("Ошибка деления на ноль")
                    return

                diff = current_value - previous_value
                ratio = current_value / previous_value
                percent = (current_value / previous_value) * 100

                set_label_text(label_diff, diff)
                set_label_text(label_ratio, ratio)
                set_label_text(label_percent, percent)
            except ValueError:
                label_diff.setText("Ошибка ввода")
                label_ratio.setText("Ошибка ввода")
                label_percent.setText("Ошибка ввода")

        comparisons = [
            (self.label_157, self.label_156, self.label_159, self.label_161, self.label_160),
            (self.label_174, self.label_172, self.label_175, self.label_176, self.label_177),
            (self.label_182, self.label_180, self.label_183, self.label_184, self.label_185),
            (self.label_166, self.label_164, self.label_167, self.label_168, self.label_169),
            (self.label_150, self.label_148, self.label_151, self.label_152, self.label_153),
        ]

        for current, previous, diff, ratio, percent in comparisons:
            handle_comparison(current, previous, diff, ratio, percent)

        # Отправка данных в GPT и установка ответа в label_139
        self.send_to_gpt()

    def send_to_gpt(self):
        u1_values = (self.label_156.text(), self.label_158.text(), self.label_157.text())
        u11_values = (self.label_159.text(), self.label_161.text(), self.label_160.text())
        u2_values = (self.label_172.text(), self.label_173.text(), self.label_174.text())
        u21_values = (self.label_175.text(), self.label_176.text(), self.label_177.text())
        u3_values = (self.label_180.text(), self.label_181.text(), self.label_182.text())
        u31_values = (self.label_183.text(), self.label_184.text(), self.label_185.text())
        u4_values = (self.label_164.text(), self.label_165.text(), self.label_166.text())
        u41_values = (self.label_167.text(), self.label_168.text(), self.label_169.text())
        u5_values = (self.label_148.text(), self.label_149.text(), self.label_150.text())
        u51_values = (self.label_151.text(), self.label_152.text(), self.label_153.text())

        content = f"""
        Значения коэффициентов:
        1. Коэффициент финансового риска, U1: за 1 год, 2 год, 3 год, {u1_values}, измерительные показатели Абсолютное отклонение, Относительное отклонение, Темп роста {u11_values}
        2. Коэффициент обеспеченности собственными источниками финансирования, U2: за 1 год, 2 год, 3 год, {u2_values}, измерительные показатели Абсолютное отклонение, Относительное отклонение, Темп роста {u21_values}
        3. Коэффициент финансовой независимости (автономии), U3: за 1 год, 2 год, 3 год, {u3_values}, измерительные показатели Абсолютное отклонение, Относительное отклонение, Темп роста {u31_values}
        4. Коэффициент финансирования, U4: за 1 год, 2 год, 3 год, {u4_values}, измерительные показатели Абсолютное отклонение, Относительное отклонение, Темп роста {u41_values}
        5. Коэффициент финансовой устойчивости, U5: за 1 год, 2 год, 3 год, {u5_values}, измерительные показатели Абсолютное отклонение, Относительное отклонение, Темп роста {u51_values}

        Пожалуйста, проанализируйте эти коэффициенты и дайте рекомендации по улучшению финансовой устойчивости компании. А также какие изменения показали измерительные показатели.
        """

        response = client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=[{"role": "user", "content": content}],
        )

        self.label_139.setText(response.choices[0].message.content)

    def save_to_docx(self):
        import docx

        # Create a new Document
        doc = Document()

        # Add a title
        doc.add_heading('Финансовые коэффициенты', level=1)

        # Create a table with headers
        table = doc.add_table(rows=1, cols=4)
        hdr_cells = table.rows[0].cells
        hdr_cells[0].text = 'Коэффициент'
        hdr_cells[1].text = 'Значение'
        hdr_cells[2].text = 'Абсолютное отклонение'
        hdr_cells[3].text = 'Относительное отклонение'

        # Add rows to the table
        def add_row(coefficient, value, abs_deviation, rel_deviation):
            row_cells = table.add_row().cells
            row_cells[0].text = coefficient
            row_cells[1].text = value
            row_cells[2].text = abs_deviation
            row_cells[3].text = rel_deviation

        # Adding your data
        add_row('U1', self.label_156.text(), self.label_159.text(), self.label_161.text())
        add_row('U2', self.label_172.text(), self.label_175.text(), self.label_176.text())
        add_row('U3', self.label_180.text(), self.label_183.text(), self.label_184.text())
        add_row('U4', self.label_164.text(), self.label_167.text(), self.label_168.text())
        add_row('U5', self.label_148.text(), self.label_151.text(), self.label_152.text())

        # Add GPT response
        doc.add_heading('Анализ', level=2)
        doc.add_paragraph(self.label_139.text())

        # Open a file dialog to select a save location
        file_path, _ = QFileDialog.getSaveFileName(self, "Сохранить файл как", "", "Word Document (.docx)")

        
        if file_path:
            doc.save(file_path)
            self.show_message_box("Сохранение", f"Файл успешно сохранён: {file_path}", QMessageBox.Icon.Information)
        else:
            self.show_message_box("Сохранение", "Сохранение отменено", QMessageBox.Icon.Warning)

    def show_message_box(self, title, text, icon):
        msg_box = QMessageBox(self)
        # Set the style for the QMessageBox and its sub-elements
        msg_box.setStyleSheet("""
            QMessageBox {
                background-color: white;
            }
            QMessageBox QLabel {
                color: black;
                background-color: white;
            }
            QMessageBox QPushButton {
                background-color: white;
                color: black;
            }
            QMessageBox QIcon {
                background-color: white;
            }
        """)
        msg_box.setWindowTitle(title)
        msg_box.setText(text)
        msg_box.setIcon(icon)
        msg_box.exec()
        


def main():
    app = QApplication(sys.argv)

    auth_window = AuthorizationWindow()
    auth_window.show()

    sys.exit(app.exec())

if __name__ == "__main__":
    main()


Нужно добавить возможность вот этого в исходный код:
Провайдер сменяется g4f
g4 fиногда может быть немного глючным и доставить вам некоторые проблемы. Вы можете создать свой собственный список провайдеров и передать его, RetryProviderчтобы Clientсделать его g4fболее стабильным.


from g4f.client   import Client
from g4f.Provider import (
  ProviderA,
  ProviderB,
  ProviderC,
  RetryProvider
)

import g4f

client = Client(
    provider = RetryProvider([
        ProviderA,
        ProviderB,
        ProviderC
    ])
)

...
RetryProviderпопытается использовать первого провайдера в списке, в случае неудачи попробует использовать следующего и так далее. Обеспечение более высоких шансов на успех. Если вы хотите использовать одного провайдера с повторной попыткой, используйте его следующим образом:


from g4f.client   import Client
from g4f.Provider import OpenaiChat, RetryProvider
import g4f

client = Client(
    provider = RetryProvider([OpenaiChat],
                             single_provider_retry=True, max_retries=5)
)
Это хорошо работает, если есть очень хороший провайдер, который иногда дает сбой.

Вот провайдеры  которых нужно добавить
    You,
    Yqcloud,
    RetryProvider