Time_process / streamlit_app.py
Bikyla's picture
Rename main.py to streamlit_app.py
8a49878 verified
# Информация о модели и метриках
MODEL_INFO = {
'type': 'Регрессионная модель',
'algorithm': 'LGBMRegressor',
'features': [
'Скорость_шпинделя',
'Подача',
'Глубина_резания',
'Длина_обработки',
'Операция',
'Материал',
'Тип_инструмента'
],
'target': 'Время обработки (секунды)'
}
METRICS = {
'MSE': 379.5,
'RMSE': 19.4,
'MAE': 10.6,
'MAPE': 1.08,
'R2': 0.85
}
import streamlit as st
import pandas as pd
import matplotlib.pyplot as plt
import pickle
import os
import seaborn as sns
from matplotlib import gridspec
from datetime import datetime
# Инициализация session_state для хранения результатов
if 'results' not in st.session_state:
st.session_state.results = []
# Создаем структуру папок
if not os.path.exists('pages'):
os.makedirs('pages')
# Функция загрузки модели
@st.cache_data
def load_model(model_path):
if os.path.exists(model_path):
with open(model_path, 'rb') as f:
return pickle.load(f)
else:
st.error(f"Файл модели {model_path} не найден!")
return None
# Функция загрузки скалера
@st.cache_data
def load_scaler(scaler_path):
if os.path.exists(scaler_path):
with open(scaler_path, 'rb') as f:
return pickle.load(f)
else:
st.error(f"Файл скалера {scaler_path} не найден!")
return None
# Функция сохранения результатов
def save_result(result):
st.session_state.results.append(result) # Добавляем результат без сброса истории
# Функция очистки истории
def clear_results():
st.session_state.results = []
# Функция визуализации зависимостей
def plot_dependencies(df):
fig = plt.figure(figsize=(15, 12))
gs = gridspec.GridSpec(2, 2)
# График зависимости от скорости шпинделя
ax1 = fig.add_subplot(gs[0, 0])
sns.scatterplot(data=df, x='Скорость_шпинделя', y='Время_обработки', ax=ax1, alpha=0.6)
ax1.legend()
ax1.set_title('Зависимость от скорости шпинделя')
# График зависимости от подачи
ax2 = fig.add_subplot(gs[0, 1])
sns.scatterplot(data=df, x='Подача', y='Время_обработки', ax=ax2, alpha=0.6)
ax2.set_title('Зависимость от подачи')
# График зависимости от глубины резания
ax3 = fig.add_subplot(gs[1, 0])
sns.scatterplot(data=df, x='Глубина_резания', y='Время_обработки', ax=ax3, alpha=0.6)
ax3.set_title('Зависимость от глубины резания')
# График зависимости от длины обработки
ax4 = fig.add_subplot(gs[1, 1])
sns.scatterplot(data=df, x='Длина_обработки', y='Время_обработки', ax=ax4, alpha=0.6)
ax4.set_title('Зависимость от длины обработки')
plt.tight_layout()
st.pyplot(fig)
df = pd.read_csv('df.csv')
# Общие настройки приложения
st.set_page_config(
page_title='Прогноз времени обработки',
layout='wide',
initial_sidebar_state='auto',
page_icon='⚙️'
)
# Создание навигационного меню
st.sidebar.title('Навигация')
page = st.sidebar.radio(
"Выберите страницу",
('Главная', 'Расчет', 'История', 'О модели','Инструкция')
)
# Страница 1: Главная
if page == 'Главная':
st.title('Добро пожаловать в приложение - "Прогноз времени обработки"')
st.markdown('''
Это веб-приложение поможет вам рассчитать время обработки деталей на станках при различных входных параметрах.
''')
try:
st.image('Main.jpg', width=1000)
except Exception:
st.warning("Изображение Main.jpg не найдено")
# Страница 2: Расчет
elif page == 'Расчет':
st.title('Расчет времени обработки')
# Загрузка модели и скалера
model = load_model('model.pkl')
scaler = load_scaler('scaler.pkl')
if model is None or scaler is None:
st.stop()
# Словарь признаков
features = dict(
speed='Скорость_шпинделя',
feed='Подача',
depth='Глубина_резания',
length='Длина_обработки',
operation='Тип_операции',
material='Тип_материала',
tool='Тип_инструмента'
)
# Слайдеры и радиокнопки
speed = st.sidebar.number_input(
label=f"{features['speed']} (об/мин)",
min_value=245,
max_value=3270,
value=245,
step=1,
format='%d'
)
feed = st.sidebar.number_input(
label=f"{features['feed']} (мм/об)",
min_value=0.007,
max_value=0.538,
value=0.007,
step=0.001,
format='%.3f'
)
depth = st.sidebar.number_input(
label=f"{features['depth']} (мм)",
min_value=0.001,
max_value=3.217,
value=0.001,
step=0.001,
format='%.3f'
)
length = st.sidebar.number_input(
label=f"{features['length']} (мм)",
min_value=1.0,
max_value=324.0,
value=1.0,
step=1.0,
format='%.0f'
)
operations = st.sidebar.radio(features['operation'], ['Фрезерование', 'Точение'], horizontal=True)
materials = st.sidebar.radio(features['material'], ['Латунь', 'Чугун', 'Низкоуглеродистая_сталь'], horizontal=True)
tools = st.sidebar.radio(features['tool'], ['Твердосплавный', 'Твердосплавный_с_покрытием', 'Быстрорежущий'], horizontal=True)
# Подготовка данных
operation_to_index = {'Фрезерование': 0, 'Точение': 1}
material_to_index = {'Латунь': 0, 'Чугун': 1, 'Низкоуглеродистая_сталь': 2}
tool_to_index = {'Твердосплавный': 0, 'Твердосплавный_с_покрытием': 1, 'Быстрорежущий': 2}
if operations == 'Фрезерование':
try:
st.image('Frez.jpg', width=600)
except Exception:
st.warning("Изображение Frez.jpg не найдено")
elif operations == 'Точение':
try:
st.image('Toch.jpg', width=600)
except Exception:
st.warning("Изображение Toch.jpg не найдено")
data_df = pd.DataFrame([dict(
Скорость_шпинделя=speed,
Подача=feed,
Глубина_резания=depth,
Длина_обработки=length,
Операция=operation_to_index[operations],
Материал=material_to_index[materials],
Тип_инструмента=tool_to_index[tools]
)])
# Вывод входных данных
st.write("##### Ваши данные")
st.write(data_df)
# Расчет
if st.button("Рассчитать"):
try:
s_data_df = scaler.transform(data_df)
time_prob = model.predict(s_data_df)
st.write("## Результаты расчета")
st.write(f"Время обработки: {time_prob[0]:.2f} секунд")
# Сохранение результата сразу после расчёта
save_result({
'timestamp': datetime.now(),
'data': data_df.to_dict(),
'time': time_prob[0]
})
st.success('Результат успешно сохранен!')
except Exception as e:
st.error(f"Ошибка при расчёте: {str(e)}")
# Страница 3: История
elif page == 'История':
st.title('История расчетов')
if not st.session_state.results:
st.info('История расчетов пуста')
else:
# Создаем DataFrame из сохраненных результатов
results_df = pd.DataFrame([
{
'Номер': idx + 1,
'Дата': result['timestamp'].strftime('%d.%m.%Y %H:%M'),
'Скорость шпинделя, (об/мин)': result['data']['Скорость_шпинделя'][0],
'Подача, (мм/об)': result['data']['Подача'][0],
'Глубина резания, (мм)': result['data']['Глубина_резания'][0],
'Длина обработки, (мм)': result['data']['Длина_обработки'][0],
'Тип операции': ['Фрезерование', 'Точение'][result['data']['Операция'][0]],
'Материал': ['Латунь', 'Чугун', 'Низкоуглеродистая_сталь'][result['data']['Материал'][0]],
'Инструмент': ['Твердосплавный', 'Твердосплавный_с_покрытием', 'Быстрорежущий'][result['data']['Тип_инструмента'][0]],
'Время обработки, (сек)': result['time']
}
for idx,result in enumerate(st.session_state.results)
])
# Отображаем таблицу
st.dataframe(results_df)
# Кнопка для построения графика
if st.button('Построить график истории'):
try:
# Создаем график
fig, ax = plt.subplots(figsize=(12, 6))
plt.plot(
results_df['Номер'],
results_df['Время обработки, (сек)'],
marker='o',
linestyle='-',
color='blue'
)
# Находим минимальное значение
min_time = results_df['Время обработки, (сек)'].min()
min_index = results_df[results_df['Время обработки, (сек)'] == min_time]['Номер'].values[0]
# Отмечаем минимальное значение
plt.plot(
min_index,
min_time,
marker='o',
color='red',
markersize=10
)
plt.text(
min_index,
min_time,
f'Минимум: {min_time:.2f} сек',
verticalalignment='bottom',
horizontalalignment='center'
)
# Форматируем оси
plt.title('Динамика времени обработки по истории расчетов')
plt.xlabel('Номер расчета')
plt.ylabel('Время обработки (сек)')
plt.grid(True)
plt.xticks(results_df['Номер']) # Показываем все номера
plt.tight_layout()
st.pyplot(fig)
except Exception as e:
st.error(f"Ошибка при построении графика: {str(e)}")
# Добавляем кнопку очистки истории
if st.button('Очистить историю'):
clear_results()
st.success('История успешно очищена')
# Страница 4: Информация о модели
elif page == 'О модели':
st.title('О модели прогнозирования')
st.subheader('Информация о модели')
st.write(f"Тип модели: {MODEL_INFO['type']}")
st.write(f"Используемый алгоритм: {MODEL_INFO['algorithm']}")
st.subheader('Входные параметры')
st.write(MODEL_INFO['features'])
st.subheader('Целевая переменная')
st.write(MODEL_INFO['target'])
st.subheader('Метрики качества на тестовой выборке')
metrics_df = pd.DataFrame(METRICS.items(), columns=['Метрика', 'Значение'])
st.dataframe(metrics_df)
st.subheader('Важные характеристики')
st.markdown('''
* Модель обучена на наборе данных с 47553 наблюдений
* Данные прошли предварительную обработку (EDA)
* Использовано масштабирование признаков
* Модель показывает точность прогнозирования на тестовых данных ~85%
# Далее представлены графики зависимости времени обработки от некоторых признаков, а также карта корреляций
''')
plot_dependencies(df)
st.subheader('Корреляция параметров')
fig_corr = plt.figure(figsize=(5, 4))
sns.heatmap(df.corr(), annot=True, cmap='coolwarm', fmt=".2f")
st.pyplot(fig_corr)
# Страница 5: Инструкция
elif page == 'Инструкция':
st.title('Инструкция по работе с приложением')
st.markdown('''
* Страница "Расчёт". На данной странице требуется ввести в ручном режиме:
* Скорость шпинделя (об/мин)
* Подача (мм/об)
* Глубина резания (мм)
* Длина обработки (мм)
* Тип операции (категориальный)
* Материал (категориальный)
* Тип инструмента (категориальный)
Далее требуется нажать кнопку "Рассчитать" -> Данный предикт модели будет рассчитан и автоматически сохранён (Его можно увидеть на странице "История").
* Страница "История". На данной странице можно просматривать результаты расчётов модели.
Также имеется возможность построить график с целью определения параметров обработки деталей с минимальным временем обработки.
При необходимости нажав на кнопку "Очистить историю" можно удалить все результаты (на данный момент отсутствует возможность фильтрации и соответственно удалении только определенных результатов)
* Страница "О модели". Данная страница хранит информацию об используемой в приложении модели, параметрах обучения, графиков и т.д.
''')