/
aiv123
/
ThermoPro
Обзор
Документация
Войти
/
aiv123
/
ThermoPro
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
gor/gor.py
552 строки
26 KB
Игорь Ананченко
Калькулятор эффективности сжигания топлива - с графическим интерфейсом
26 фев 2026, 15:37
Верифицирован
26 фев 2026, 15:37
e0f3bed
Код
Авторство
О чём код?
import tkinter as tk from tkinter import ttk, messagebox import requests from openai import OpenAI import re import math import os class FuelCalculator: def __init__(self, root): self.root = root self.root.title("Калькулятор эффективности сжигания топлива") self.root.geometry("1100x900") # Чтение config.dat try: with open("config.dat", "r", encoding="utf-8") as f: lines = f.read().splitlines() self.API_KEY = lines[0].strip() self.MODEL_NAME = lines[1].strip() except Exception as e: messagebox.showerror("Ошибка", f"Ошибка чтения config.dat:\n{e}") root.destroy() return self.openai_client = OpenAI(api_key=self.API_KEY, base_url="https://api.proxyapi.ru/openai/v1") self.conversation_history = [] self.step1_done = False self.step2_done = False self.step3_done = False # Создание специального стиля для виджетов ttk.Entry style = ttk.Style() style.configure("ResultField.TEntry", fieldbackground="#B2FFE1", foreground="red") # Фон светло-зеленый, шрифт красный self.create_widgets() self.update_ro2max() # Получаем число из Entry def get_float(self, entry): try: return float(entry.get().replace(",", ".")) except ValueError: return None # Обновляем значение RO2max def update_ro2max(self, event=None): fuel = self.combo_fuel.current() if fuel == 0: value = "11.8" elif fuel == 1: value = "16" else: value = "18.7" self.entry_ro2max.config(state="normal") self.entry_ro2max.delete(0, tk.END) self.entry_ro2max.insert(0, value) if not self.var_ro2_edit.get(): self.entry_ro2max.config(state="readonly") # Включаем возможность вручную изменить RO2max def toggle_ro2_edit(self): if self.var_ro2_edit.get(): self.entry_ro2max.config(state="normal") else: self.update_ro2max() # Первая вкладка def calculate_tab1(self): RO2max = self.get_float(self.entry_ro2max) O2 = self.get_float(self.entry_o2) CO = self.get_float(self.entry_co) if any(val is None for val in [RO2max, O2, CO]): messagebox.showerror("Ошибка", "Проверьте корректность ввода данных") return CO_frac = CO / 10000 self.RO2 = (RO2max * (21 - O2 + 0.4 * CO_frac)) / 21 - CO_frac self.N2 = 100 - O2 - self.RO2 - CO_frac self.alpha = self.N2 / (self.N2 - 3.76 * (O2 - 0.5 * CO_frac)) self.var_ro2.set(f"{self.RO2:.4f}") self.var_n2.set(f"{self.N2:.4f}") self.var_alpha.set(f"{self.alpha:.4f}") # Проставляем специальные стили для полей ro2_entry = self.tab1.nametowidget("ro2_entry") n2_entry = self.tab1.nametowidget("n2_entry") alpha_entry = self.tab1.nametowidget("alpha_entry") ro2_entry.configure(style="ResultField.TEntry") n2_entry.configure(style="ResultField.TEntry") alpha_entry.configure(style="ResultField.TEntry") self.step1_done = True self.enable_tab2() # Вторая вкладка def calculate_tab2(self): if not self.step1_done: messagebox.showerror("Ошибка", "Сначала выполните расчёт на вкладке 1") return t_air = self.get_float(self.entry_t_air) t_gas = self.get_float(self.entry_t_gas) if any(val is None for val in [t_air, t_gas]): messagebox.showerror("Ошибка", "Проверьте корректность ввода данных") return fuel = self.combo_fuel.current() if fuel == 0: A1, B = 0.37, 0.009 elif fuel == 1: A1, B = 0.52, 0.007 else: A1, B = 0.59, 0.009 self.q2 = (A1 / self.RO2 + B) * (t_gas - t_air) self.h = float(self.entry_ro2max.get()) / (self.RO2 + float(self.entry_co.get()) / 10000) self.q3 = self.h * (3 * float(self.entry_co.get()) / 10000) self.eff_burning = 100 - (self.q2 + self.q3) self.var_h.set(f"{self.h:.4f}") self.var_q2.set(f"{self.q2:.4f}") self.var_q3.set(f"{self.q3:.4f}") self.var_eff_burning.set(f"{self.eff_burning:.4f}") # Проставляем специальные стили для полей h_entry = self.tab2.nametowidget("h_entry") q2_entry = self.tab2.nametowidget("q2_entry") q3_entry = self.tab2.nametowidget("q3_entry") efficiency_entry = self.tab2.nametowidget("efficiency_entry") h_entry.configure(style="ResultField.TEntry") q2_entry.configure(style="ResultField.TEntry") q3_entry.configure(style="ResultField.TEntry") efficiency_entry.configure(style="ResultField.TEntry") self.step2_done = True self.enable_tab3() # Третья вкладка def update_boiler_labels(self, event=None): boiler_type = self.combo_boiler.current() if boiler_type == 0: label_text_nom = "Номинальная тепловая нагрузка агрегата (Nном) в МВт " label_text_fact = "Фактическая тепловая нагрузка агрегата (Nфакт) в МВт " else: label_text_nom = "Номинальная паропроизводительность агрегата (Dном) в т/ч " label_text_fact = "Фактическая паропроизводительность агрегата (Dфакт) в т/ч " self.label_nom.config(text=label_text_nom) self.label_fact.config(text=label_text_fact) def calculate_tab3(self): if not self.step2_done: messagebox.showerror("Ошибка", "Сначала выполните расчёт на вкладке 2") return nominal_load = self.get_float(self.entry_nom) actual_load = self.get_float(self.entry_fact) if any(val is None for val in [nominal_load, actual_load]) or actual_load == 0: messagebox.showerror("Ошибка", "Проверьте корректность ввода данных") return boiler_type = self.combo_boiler.current() analysis_type = self.combo_analysis.current() if boiler_type == 0: if analysis_type == 0: self.q5nom = 4.0973 * pow(nominal_load, -0.803) else: self.q5nom = 4.477 * pow(nominal_load, -0.532) else: if analysis_type == 0: self.q5nom = 6.1751 * pow(nominal_load, -0.803) else: self.q5nom = 5.8745 * pow(nominal_load, -0.532) self.q5 = self.q5nom * (nominal_load / actual_load) self.eff_gross = self.eff_burning - self.q5 self.var_q5nom.set(f"{self.q5nom:.4f}") self.var_q5.set(f"{self.q5:.4f}") self.var_eff_gross.set(f"{self.eff_gross:.4f}") # Проставляем специальные стили для полей q5nom_entry = self.tab3.nametowidget("q5nom_entry") q5_entry = self.tab3.nametowidget("q5_entry") gross_efficiency_entry = self.tab3.nametowidget("gross_efficiency_entry") q5nom_entry.configure(style="ResultField.TEntry") q5_entry.configure(style="ResultField.TEntry") gross_efficiency_entry.configure(style="ResultField.TEntry") self.step3_done = True self.enable_tab4() # Четвертая вкладка def calculate_tab4(self): if not self.step3_done: messagebox.showerror("Ошибка", "Сначала выполните расчёт на вкладке 3") return qsn = self.get_float(self.entry_qsn) if qsn is None: messagebox.showerror("Ошибка", "Проверьте корректность ввода данных") return eff_net = self.eff_gross - qsn self.var_eff_net.set(f"{eff_net:.4f}") # Проставляем специальный стиль для поля net_efficiency_entry = self.tab4.nametowidget("net_efficiency_entry") net_efficiency_entry.configure(style="ResultField.TEntry") # Начало диалога с ИИ def start_dialog(self): self.conversation_history = [] self.chat_text.delete("1.0", tk.END) self.chat_text.insert(tk.END, f"Вы работаете с моделью искусственного интеллекта - {self.MODEL_NAME}\n\n") # Форматирование текста перед вставкой def format_and_insert(self, text): # Обработка специальных символов text = text.replace("\n", "\n").replace("\t", " ") text = re.sub(r"\*\*(.*?)\*\*", r"\1", text) for line in text.split("\n"): if line.strip().startswith("[") or line.strip().startswith("$"): self.chat_text.insert(tk.END, line + "\n", "formula") else: self.chat_text.insert(tk.END, line + "\n") self.chat_text.insert(tk.END, "\n") # Копируем диалог в буфер обмена def copy_to_clipboard(self): dialog_text = self.chat_text.get("1.0", tk.END) self.root.clipboard_clear() self.root.clipboard_append(dialog_text) messagebox.showinfo("Готово", "Диалог скопирован в буфер обмена.") # Копируем диалог в файл def save_to_file(self): dialog_text = self.chat_text.get("1.0", tk.END) filename = "AI-log.txt" mode = "a" if os.path.exists(filename) else "w" with open(filename, mode, encoding='utf-8') as f: f.write(dialog_text) messagebox.showinfo("Готово", f"Диалог сохранён в файл '{filename}'.") # Метод отправки сообщения def send_message(self): user_text = self.entry_chat.get().strip() if not user_text: return # Выводим сообщение пользователя self.chat_text.insert(tk.END, "Вы: " + user_text + "\n\n") # Показываем уведомление ожидания self.chat_text.insert(tk.END, "Ждите ответа ИИ...\n\n") self.chat_text.see(tk.END) # Отложенная отправка запроса на сервер через таймер (например, через 1 мс) self.root.after(1, lambda: self.process_request(user_text)) # Новый метод обработки запроса def process_request(self, user_text): self.conversation_history.append({"role": "user", "content": user_text}) try: response = self.openai_client.chat.completions.create( model=self.MODEL_NAME, messages=self.conversation_history ) reply = response.choices[0].message.content self.conversation_history.append({"role": "assistant", "content": reply}) # Вставляем ответ ИИ с обработкой формул self.format_and_insert("ИИ: " + reply) # Удаляем строку уведомления ожидания last_line_start = int(self.chat_text.index('end').split('.')[0]) - 2 self.chat_text.delete(f'{last_line_start}.0', f'{last_line_start+1}.0') except Exception as e: messagebox.showerror("Ошибка ИИ", str(e)) # Проверяем баланс API ключа def check_balance(self): url = 'https://api.proxyapi.ru/proxyapi/balance' headers = {'Authorization': f'Bearer {self.API_KEY}'} try: response = requests.get(url, headers=headers) if response.status_code == 200: data = response.json() balance = data['balance'] text = f"Общий баланс: {balance:.2f}\n" if data.get('budget'): budget = data['budget'] text += f"\nЛимит бюджета: {budget['limit']:.2f}\n" text += f"Использовано: {budget['used']:.2f}\n" text += f"Осталось: {balance:.2f}\n" self.balance_text.delete("1.0", tk.END) self.balance_text.insert(tk.END, text) else: messagebox.showerror("Ошибка", f"Ошибка сервера ({response.status_code})") except Exception as e: messagebox.showerror("Ошибка", str(e)) # Заблокировать элементы вкладки def disable_children(self, frame): for child in frame.winfo_children(): try: child.configure(state="disabled") except: pass # Разблокировать элементы вкладки def enable_children(self, frame): for child in frame.winfo_children(): try: child.configure(state="normal") except: pass # Открыть вкладку 2 def enable_tab2(self): self.enable_children(self.tab2) # Открыть вкладку 3 def enable_tab3(self): self.enable_children(self.tab3) # Открыть вкладку 4 def enable_tab4(self): self.enable_children(self.tab4) # Графический интерфейс def create_widgets(self): notebook = ttk.Notebook(self.root) notebook.pack(fill="both", expand=True) # Вкладка 1 ("Продукты сгорания") self.tab1 = ttk.Frame(notebook) notebook.add(self.tab1, text="1. Продукты сгорания") # Интерфейс вкладки 1 ttk.Label(self.tab1, text="Выберите вид топлива:").grid(row=0, column=0, sticky="W", padx=5) self.combo_fuel = ttk.Combobox(self.tab1, values=["Природный газ", "Мазут", "Уголь"], state="readonly") self.combo_fuel.current(0) self.combo_fuel.grid(row=0, column=1, padx=5) self.combo_fuel.bind("<<ComboboxSelected>>", self.update_ro2max) ttk.Label(self.tab1, text="RO2max (%):").grid(row=1, column=0, sticky="W", padx=5) self.entry_ro2max = ttk.Entry(self.tab1) self.entry_ro2max.grid(row=1, column=1, padx=5) self.var_ro2_edit = tk.BooleanVar() ttk.Checkbutton(self.tab1, text="Редактировать RO2max:", variable=self.var_ro2_edit, command=self.toggle_ro2_edit).grid(row=1, column=2, padx=5) ttk.Label(self.tab1, text="Концентрация кислорода в продуктах сгорания (O₂) в об.%:").grid(row=2, column=0, sticky="W", padx=5) self.entry_o2 = ttk.Entry(self.tab1) self.entry_o2.grid(row=2, column=1, padx=5) ttk.Label(self.tab1, text="Концентрация продуктов неполного сгорания (CO) в ppm:").grid(row=3, column=0, sticky="W", padx=5) self.entry_co = ttk.Entry(self.tab1) self.entry_co.grid(row=3, column=1, padx=5) # Кнопка расчета расположена ниже чекбокса button_calculate = ttk.Button(self.tab1, text="Рассчитать", command=self.calculate_tab1) button_calculate.grid(row=4, column=2, pady=(10, 0), padx=8) button_calculate["style"] = "CustomButtonStyle.TButton" # Бирюзовый фон для кнопки self.var_ro2 = tk.StringVar() self.var_n2 = tk.StringVar() self.var_alpha = tk.StringVar() ttk.Label(self.tab1, text="RO₂ (%):").grid(row=5, column=0, sticky="W", padx=5) entry_ro2 = ttk.Entry(self.tab1, textvariable=self.var_ro2, state="readonly", name="ro2_entry") entry_ro2.grid(row=5, column=1, padx=5) ttk.Label(self.tab1, text="Концентрация N₂ в продуктах сгорания в об. %:").grid(row=6, column=0, sticky="W", padx=5) entry_n2 = ttk.Entry(self.tab1, textvariable=self.var_n2, state="readonly", name="n2_entry") entry_n2.grid(row=6, column=1, padx=5) ttk.Label(self.tab1, text="Коэффициент избытка воздуха α:").grid(row=7, column=0, sticky="W", padx=5) entry_alpha = ttk.Entry(self.tab1, textvariable=self.var_alpha, state="readonly", name="alpha_entry") entry_alpha.grid(row=7, column=1, padx=5) # Вкладка 2 ("Потери") self.tab2 = ttk.Frame(notebook) notebook.add(self.tab2, text="2. Потери") # Интерфейс вкладки 2 ttk.Label(self.tab2, text="Температура дутьевого воздуха в °C:").grid(row=0, column=0, sticky="W", padx=5) self.entry_t_air = ttk.Entry(self.tab2) self.entry_t_air.grid(row=0, column=1, padx=5) ttk.Label(self.tab2, text="Температура уходящих газов в °C:").grid(row=1, column=0, sticky="W", padx=5) self.entry_t_gas = ttk.Entry(self.tab2) self.entry_t_gas.grid(row=1, column=1, padx=5) button_calculate_tab2 = ttk.Button(self.tab2, text="Рассчитать", command=self.calculate_tab2) button_calculate_tab2.grid(row=2, columnspan=2, pady=(10, 0), padx=5) button_calculate_tab2["style"] = "CustomButtonStyle.TButton" # Бирюзовый фон для кнопки self.var_h = tk.StringVar() self.var_q2 = tk.StringVar() self.var_q3 = tk.StringVar() self.var_eff_burning = tk.StringVar() ttk.Label(self.tab2, text="Коэффициент разбавления сухих продуктов сгорания (h): ").grid(row=3, column=0, sticky="W", padx=5) entry_h = ttk.Entry(self.tab2, textvariable=self.var_h, state="readonly", name="h_entry") entry_h.grid(row=3, column=1, padx=5) ttk.Label(self.tab2, text="Потеря тепла с уходящими газами Q₂ в (%):").grid(row=4, column=0, sticky="W", padx=5) entry_q2 = ttk.Entry(self.tab2, textvariable=self.var_q2, state="readonly", name="q2_entry") entry_q2.grid(row=4, column=1, padx=5) ttk.Label(self.tab2, text="Потери тепла от химнедожога Q₃ в (%):").grid(row=5, column=0, sticky="W", padx=5) entry_q3 = ttk.Entry(self.tab2, textvariable=self.var_q3, state="readonly", name="q3_entry") entry_q3.grid(row=5, column=1, padx=5) ttk.Label(self.tab2, text="КПД горения в %. Эффективность горения (%):").grid(row=6, column=0, sticky="W", padx=5) entry_efficiency = ttk.Entry(self.tab2, textvariable=self.var_eff_burning, state="readonly", name="efficiency_entry") entry_efficiency.grid(row=6, column=1, padx=5) # Третья вкладка self.tab3 = ttk.Frame(notebook) notebook.add(self.tab3, text="3. Агрегат") # Интерфейс вкладки 3 ttk.Label(self.tab3, text="Тип котла:").grid(row=0, column=0, sticky="W", padx=5) self.combo_boiler = ttk.Combobox(self.tab3, values=["Водогрейный", "Паровой"], state="readonly") self.combo_boiler.current(0) self.combo_boiler.grid(row=0, column=1, padx=5) self.combo_boiler.bind("<<ComboboxSelected>>", self.update_boiler_labels) ttk.Label(self.tab3, text="Анализ отходящих газов выполнен:").grid(row=1, column=0, sticky="W", padx=5) self.combo_analysis = ttk.Combobox(self.tab3, values=["за котлом", "за котлоагрегатом"], state="readonly") self.combo_analysis.current(0) self.combo_analysis.grid(row=1, column=1, padx=5) self.label_nom = ttk.Label(self.tab3) self.label_nom.grid(row=2, column=0, sticky="W", padx=5) self.entry_nom = ttk.Entry(self.tab3) self.entry_nom.grid(row=2, column=1, padx=5) self.label_fact = ttk.Label(self.tab3) self.label_fact.grid(row=3, column=0, sticky="W", padx=5) self.entry_fact = ttk.Entry(self.tab3) self.entry_fact.grid(row=3, column=1, padx=5) self.update_boiler_labels() button_calculate_tab3 = ttk.Button(self.tab3, text="Рассчитать", command=self.calculate_tab3) button_calculate_tab3.grid(row=4, columnspan=2, pady=(10, 0), padx=5) button_calculate_tab3["style"] = "CustomButtonStyle.TButton" # Бирюзовый фон для кнопки self.var_q5nom = tk.StringVar() self.var_q5 = tk.StringVar() self.var_eff_gross = tk.StringVar() ttk.Label(self.tab3, text="Q₅ ном (%):").grid(row=5, column=0, sticky="W", padx=5) entry_q5nom = ttk.Entry(self.tab3, textvariable=self.var_q5nom, state="readonly", name="q5nom_entry") entry_q5nom.grid(row=5, column=1, padx=5) ttk.Label(self.tab3, text="Потери тепла в окружающую среду Q₅ в %:").grid(row=6, column=0, sticky="W", padx=5) entry_q5 = ttk.Entry(self.tab3, textvariable=self.var_q5, state="readonly", name="q5_entry") entry_q5.grid(row=6, column=1, padx=5) ttk.Label(self.tab3, text="КПД теплового агрегата 'брутто' в %:").grid(row=7, column=0, sticky="W", padx=5) entry_gross_efficiency = ttk.Entry(self.tab3, textvariable=self.var_eff_gross, state="readonly", name="gross_efficiency_entry") entry_gross_efficiency.grid(row=7, column=1, padx=5) # Четвертая вкладка self.tab4 = ttk.Frame(notebook) notebook.add(self.tab4, text="4. Итог") # Интерфейс вкладки 4 ttk.Label(self.tab4, text="Потери тепла на собственные нужды Qс.н. (%):").grid(row=0, column=0, sticky="W", padx=5) self.entry_qsn = ttk.Entry(self.tab4) self.entry_qsn.grid(row=0, column=1, padx=5) button_calculate_tab4 = ttk.Button(self.tab4, text="Рассчитать", command=self.calculate_tab4) button_calculate_tab4.grid(row=1, columnspan=2, pady=(10, 0), padx=5) button_calculate_tab4["style"] = "CustomButtonStyle.TButton" # Бирюзовый фон для кнопки self.var_eff_net = tk.StringVar() ttk.Label(self.tab4, text="КПД теплового агрегата 'нетто' в %").grid(row=2, column=0, sticky="W", padx=5) entry_net_efficiency = ttk.Entry(self.tab4, textvariable=self.var_eff_net, state="readonly", name="net_efficiency_entry") entry_net_efficiency.grid(row=2, column=1, padx=5) # Вкладка 5 ("Диалог с ИИ") self.tab5 = ttk.Frame(notebook) notebook.add(self.tab5, text="5. Диалог с ИИ") # Интерфейс вкладки 5 frame_chat = ttk.Frame(self.tab5, padding=20) frame_chat.pack(fill="both", expand=True) ttk.Button(frame_chat, text="Начать диалог с ИИ", command=self.start_dialog).pack(anchor="w") self.chat_text = tk.Text(frame_chat, wrap="word") self.chat_text.pack(fill="both", expand=True, pady=10) self.chat_text.tag_config("formula", foreground="blue") self.entry_chat = ttk.Entry(frame_chat) self.entry_chat.pack(fill="x") ttk.Button(frame_chat, text="Отправить сообщение", command=self.send_message).pack(anchor="w", pady=5) ttk.Button(frame_chat, text="Скопировать диалог в буфер обмена", command=self.copy_to_clipboard).pack(side="left", anchor="w", pady=5) ttk.Button(frame_chat, text="Скопировать диалог в файл AI-log.txt", command=self.save_to_file).pack(side="right", anchor="w", pady=5) # Вкладка 6 ("Баланс") self.tab6 = ttk.Frame(notebook) notebook.add(self.tab6, text="6. Баланс") # Интерфейс вкладки 6 frame_balance = ttk.Frame(self.tab6, padding=20) frame_balance.pack(fill="both", expand=True) ttk.Button(frame_balance, text="Проверить баланс", command=self.check_balance).pack(anchor="w") self.balance_text = tk.Text(frame_balance, height=10) self.balance_text.pack(fill="both", expand=True, pady=10) # Начальная блокировка вкладок self.disable_children(self.tab2) self.disable_children(self.tab3) self.disable_children(self.tab4) if __name__ == "__main__": root = tk.Tk() app = FuelCalculator(root) root.mainloop()