File size: 16,523 Bytes
21233df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
# Информация о модели и метриках
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('''

    * Страница "Расчёт". На данной странице требуется ввести в ручном режиме:

        * Скорость шпинделя (об/мин)

        * Подача (мм/об)

        * Глубина резания (мм)

        * Длина обработки (мм)

        * Тип операции (категориальный)

        * Материал (категориальный)

        * Тип инструмента (категориальный)

        

        Далее требуется нажать кнопку "Рассчитать" -> Данный предикт модели будет рассчитан и автоматически сохранён (Его можно увидеть на странице "История").

    

    

    

    * Страница "История". На данной странице можно просматривать результаты расчётов модели.

    

    Также имеется возможность построить график с целью определения параметров обработки деталей с минимальным временем обработки.

    

    При необходимости нажав на кнопку "Очистить историю" можно удалить все результаты (на данный момент отсутствует возможность фильтрации и соответственно удалении только определенных результатов)

    

    

    * Страница "О модели". Данная страница хранит информацию об используемой в приложении модели, параметрах обучения, графиков и т.д.

    ''')